To use the SellerMagnet API as an Amazon Singapore product API, call it with marketplaceId=A19VAU5U5O7RUS: the request goes to amazon.sg and prices come back in SGD. Offers, product lookup, search, deals, bestsellers and seller feedback all answer for amazon.sg; price history, sales estimates and the ASIN converter return a free 400. Two details matter: Amazon's own offer carries no first-party seller ID on amazon.sg, and bestseller category IDs must come from amazon.sg's own tree.
Key Takeaways
- amazon.sg is marketplace A19VAU5U5O7RUS and is priced in SGD.
- Six endpoints answer on amazon.sg; statistics, estimated sales and the converter return a free 400 and no data.
- Amazon's own offer is
sellerId"Amazon" withamazonSellerIdnull on amazon.sg, so recognise Amazon bysellerId. - Bestsellers need a
category_idfrom amazon.sg's own tree (28 top-level categories); an ID from another store's tree gets a free 400 and no data. - amazon.sg pages are read in English, so
listedSinceDatecan be filled, unlike on the Arabic-language stores.
What is different about the Amazon Singapore product API?
The request format is the same as for every other store: GET, query parameters, the key in the X-Api-Key header. What changes are a few values, the endpoint coverage and how Amazon's own offer is labelled. Prices come back as plain decimal numbers in SGD; the S$ symbol is for display only, and currency_code tells you the currency.
| Item | amazon.sg |
|---|---|
| Marketplace ID | A19VAU5U5O7RUS |
| Store | amazon.sg |
| Currency | SGD (Singapore Dollar), symbol S$ |
| Default postcode | 179431, used when you send no geo_location |
| Page language | English |
| Amazon's own offer | sellerId "Amazon", amazonSellerId null |
| Bestseller category tree | amazon.sg's own: 28 top-level categories |
| History endpoints | free 400, no data |
The amazon.sg entry of /amazon-get-marketplaces as sent (keyed by marketplace ID)
{
"A19VAU5U5O7RUS": {
"currency_code": "SGD",
"currency_name": "Singapore Dollar",
"currency_symbol": "S$",
"geo_location": "179431",
"marketplace_domain": "amazon.sg",
"marketplace_name": "Amazon SG"
}
}
Amazon's own APIs answer different questions. The Selling Partner API is for sellers and the apps they authorise, and the Creators API, which replaces the deprecated Product Advertising API 5, is for affiliates: Amazon requires at least 10 qualifying sales within the past 30 days for access. To read any amazon.sg listing, its offers and its bestsellers without a seller or affiliate account, the endpoints below need only an API key.
Recognising Amazon's own offer on amazon.sg
On most marketplaces an offer from Amazon itself comes back with sellerId "Amazon" and its first-party seller ID in amazonSellerId, for example ATVPDKIKX0DER on amazon.com. The API has no such ID for amazon.sg (nor for amazon.in), so there amazonSellerId is null on every offer, Amazon's included. A check like if offer["amazonSellerId"] therefore never finds Amazon on amazon.sg. Test sellerId == "Amazon" instead; it works on all 23 marketplaces. The is Amazon selling on this listing guide covers the same check across stores.

Endpoint coverage on amazon.sg
Six of the ten endpoints only check that the marketplace ID is valid, so they answer on all 23 marketplaces, amazon.sg included. The three history endpoints cover only 11 marketplaces and turn every other one away before the credit is taken: amazon.sg gets a 400 with the message "This endpoint is not available for the requested marketplace" followed by the list of supported stores. That call costs nothing, but it returns no data either. In the region only amazon.co.jp and amazon.in have history; amazon.com.au and amazon.sg do not.

How do I check amazon.sg bestsellers in Python?
The script below reads the top five bestsellers of one amazon.sg category, then the live offers of each ASIN, and prints the bestseller card price next to the featured offer's item price and shipping, in SGD. Before any call, it rejects a category ID that is neither a slug nor a numeric ID and a count outside 1 to 50 (the API bills that count as a 400); it queries an ASIN that fills two cards only once and stops the whole run on a 401/403. It uses sellermagnet.py (ApiError, new_session) and retry.py (get_with_retry) from the Python quickstart.
sg_bestsellers.py - who holds the featured offer on the amazon.sg bestsellers
"""Amazon Singapore (amazon.sg) bestseller check: who holds the featured offer on the top products, in SGD.
amazon.sg is marketplace A19VAU5U5O7RUS, priced in SGD. Three things this script relies on:
1. Bestsellers take a category_id from amazon.sg's OWN category tree (the category explorer on
sellermagnet-api.com). An ID from another store's tree is a free 400 "Invalid CategoryId".
2. The API has no first-party seller ID for amazon.sg: Amazon's own offer comes back as sellerId "Amazon"
with amazonSellerId null. So Amazon is recognised by sellerId, never by amazonSellerId.
3. amazon.sg is not one of the 11 marketplaces with price history: statistics, estimated sales and the ASIN
converter answer it with a free 400. The script never sends those calls.
Helpers: sellermagnet.py and retry.py from https://sellermagnet-api.com/blog/amazon-product-api-python
"""
import re
import requests
from retry import get_with_retry
from sellermagnet import ApiError, new_session
MARKET = "A19VAU5U5O7RUS" # amazon.sg, prices in SGD
CATEGORY = "6436074051" # Electronics > Mobile Phones and Communication in amazon.sg's tree
TOP = 5 # bestseller cards to check; 1 to 50 (a bestseller page holds 50)
HISTORY_MARKETS = {"ATVPDKIKX0DER", "A2EUQ1WTGCTBG2", "A1AM78C64UM0Y8", "A2Q3Y263D00KWC", "A1F83G8C2ARO7P",
"A1PA6795UKMFR9", "A13V1IB3VIYZZH", "APJ6JRA9NG5V4", "A1RKKUPIHCS9HS", "A21TJRUUN4KGV",
"A1VC38T7YXB528"} # the 11 marketplaces with statistics, estimated sales, converter
MAX_FAILED = 3 # 502/503 are billed on every attempt: stop after 3 calls that keep failing
class Stop(Exception):
"""401/403: the key or the credits are the problem, so every further call would fail the same way."""
def call(session, endpoint, **params):
try:
return get_with_retry(session, endpoint, **params)
except ApiError as err:
if err.status in (401, 403):
raise Stop(str(err)) from err
raise
def check_inputs(category, top):
"""Check before any call: a count outside 1 to 50 is a billed 400, and the category must be an ID."""
category = str(category).strip().lower() # the API matches IDs case-insensitively
if not re.fullmatch(r"[a-z0-9-]+", category):
return None, f"category_id {category!r} is not a slug or a numeric ID"
if not isinstance(top, int) or not 1 <= top <= 50:
return None, f"TOP={top!r}: count must be a whole number from 1 to 50"
return category, ""
def top_asins(cards, top):
"""Unique ASINs in rank order; cards without an ASIN are counted, not queried."""
seen, picked, no_asin = set(), [], 0
for card in cards:
asin = str(card.get("asin") or "").strip().upper()
if not re.fullmatch(r"[A-Z0-9]{10}", asin):
no_asin += 1
continue
if asin in seen: # the same product can fill two cards
continue
seen.add(asin)
price = (card.get("price") or {}).get("price")
picked.append((card.get("rank") or "-", asin, price if isinstance(price, (int, float)) else None))
return picked[:top], no_asin
def featured(data):
"""(item, shipping, holder, unique sellers, Amazon among the offers); item None when nothing is featured."""
box, offers = data.get("buyBox") or {}, data.get("offers") or []
sellers = len({o.get("sellerId") for o in offers if o.get("sellerId")}) # a seller can be listed twice
amazon_listed = any(o.get("sellerId") == "Amazon" for o in offers)
item = box.get("priceWithoutShipping") or 0.0
if data.get("buyBoxSuppressed") or item <= 0: # 0.0 = no readable price, never a real price
return None, None, "no featured offer", sellers, amazon_listed
if box.get("sellerId") == "Amazon": # amazonSellerId stays null on amazon.sg
holder = "Amazon"
else:
holder = f"{box.get('fulfillmentType', '?')} seller {box.get('sellerId', '?')}"
return round(item, 2), round(box.get("shippingPrice") or 0.0, 2), holder, sellers, amazon_listed
def row(rank, asin, card="-", item="-", ship="-", sellers="-", note=""):
print(f"{rank!s:>4} {asin:<10} {card:>8} {item:>8} {ship:>6} {sellers:>7} {note}")
def main():
history = "yes" if MARKET in HISTORY_MARKETS else "not available (free 400), not called"
category, problem = check_inputs(CATEGORY, TOP)
if problem:
print(f"skipped before any call: {problem}")
return
session = new_session()
try:
data = call(session, "amazon-bestsellers", category_id=category, marketplaceId=MARKET, count=TOP)
except Stop as err:
print(f"stopped: {err}")
return
except ApiError as err:
hint = " (free 400: take the ID from amazon.sg's own tree)" if "CategoryId" in str(err) else ""
print(f"bestsellers failed: {err}{hint}")
return
except (requests.ConnectionError, requests.Timeout) as err:
print(f"bestsellers failed: {type(err).__name__}")
return
asins, no_asin = top_asins(data.get("bestsellers") or [], TOP)
print(f"amazon.sg bestsellers, category {category}: {len(asins)} ASINs to check, "
f"{no_asin} card(s) without an ASIN")
print(f"price history on amazon.sg: {history}")
print()
row("rank", "asin", "card", "item", "ship", "sellers", "featured offer (SGD)")
failed = amazon_holds = checked = 0
for rank, asin, card in asins:
if failed >= MAX_FAILED:
print(f"stopped after {MAX_FAILED} failed calls")
break
card_txt = f"{card:.2f}" if card is not None else "-"
try:
offers = call(session, "amazon-product-offers", asin=asin, marketplaceId=MARKET)
except Stop as err:
print(f"stopped: {err}")
break
except ApiError as err:
note = "not found on amazon.sg (billed 404)" if err.status == 404 else f"error {err}"
row(rank, asin, card_txt, note=note)
failed += err.status >= 500
continue
except (requests.ConnectionError, requests.Timeout) as err:
row(rank, asin, card_txt, note=f"error {type(err).__name__}")
failed += 1
continue
checked += 1
item, ship, holder, sellers, amazon_listed = featured(offers)
if item is None:
row(rank, asin, card_txt, sellers=sellers, note=holder)
continue
amazon_holds += holder == "Amazon"
if holder != "Amazon" and amazon_listed:
holder += ", Amazon also offers it"
row(rank, asin, card_txt, f"{item:.2f}", f"{ship:.2f}", sellers, holder)
print(f"\nAmazon holds the featured offer on {amazon_holds} of {checked} products read")
if __name__ == "__main__":
main()
Output (illustrative data: a retried 502, a card without an ASIN, a listing without offers)
amazon.sg bestsellers, category 6436074051: 4 ASINs to check, 1 card(s) without an ASIN
price history on amazon.sg: not available (free 400), not called
rank asin card item ship sellers featured offer (SGD)
1 B0SGPHONE1 18.90 18.90 0.00 2 Amazon
2 B0SGCABLE2 12.99 12.99 0.00 2 FBA seller A2SGSELLER02, Amazon also offers it
3 B0SGCASE03 9.90 - - 0 no featured offer
5 B0SGPOWER5 39.90 37.90 0.00 1 Amazon
Amazon holds the featured offer on 2 of 4 products read
- Amazon in the last column means the featured offer has
sellerId"Amazon"; itsamazonSellerIdwas null, as on every amazon.sg offer. - Amazon also offers it marks a product where a third-party seller holds the featured offer while Amazon has an offer in the list too.
- card is the price on the bestseller page and item the featured offer's price without shipping. They can differ (rank 5), because the card is not taken from the featured offer (a variation range shows its low end there), so compare the item column when you track prices.
- sellers counts distinct seller IDs: the offers list can show the same seller twice (different delivery date or condition), so
len(offers)overcounts. - no featured offer with 0 sellers is a listing without offers on that page, not an error. Confirm a stock-out with a second check before acting on it. Rank 4 is missing because its card carried no ASIN.
amazon.sg has its own bestseller category tree
amazon.ie borrows the UK category tree because it has none of its own; amazon.sg is not in that alias list and has its own tree with 28 top-level categories and 13,936 nodes. The names are in English, the top level uses slugs such as electronics or amazon-global-store, and deeper IDs are numeric (Electronics > Mobile Phones and Communication is 6436074051). Those numeric IDs are specific to amazon.sg: none of them appears in the amazon.com, amazon.com.au or amazon.in tree. Take category_id from the category explorer; an ID from another marketplace's tree fails with "Invalid CategoryId", a free 400 that is answered before the credit is taken.
Does listedSinceDate work on amazon.sg?
It can. The API reads amazon.sg in English, and the label list it uses to find a product's "Date First Available" row includes the English phrase, which is the label amazon.sg product pages show (for example "Date First Available: 29 December 2022"). So productInfo.listedSinceDate from product lookup is filled when the page has that row, the same as on amazon.com.au. A null still happens on pages without the row; it does not mean the listing is new. Titles and category names come back in English, and prices use the comma-thousands, dot-decimal format, already converted to numbers.
Credit cost of an amazon.sg check
1 credit per request, as on every store. The script costs 1 credit for the bestsellers call plus 1 credit per ASIN for its offers, plus each billed retry: a 502 or 503 is charged on every attempt, a 500 without Retry-After is refunded. A 404 for an ASIN is billed, and so is a 400 for a count above 50; an invalid marketplace ID, an unknown category ID and the history endpoints' amazon.sg 400 are free. The example run made 6 calls: 1 for the bestsellers, 4 for the four ASINs and 1 retried 502. For every store at once, see API marketplace coverage.
Frequently Asked Questions
What is the Amazon Singapore marketplace ID?
A19VAU5U5O7RUS. Pass it as marketplaceId and the request goes to amazon.sg, with prices in SGD. A country code like "SG" or a domain like "amazon.sg" is rejected with a free 400 Invalid marketplaceId.
How do I know if Amazon itself sells a product on amazon.sg?
Look for an offer with sellerId "Amazon". On amazon.sg the API has no first-party seller ID, so amazonSellerId stays null even on Amazon's own offer. Code that waits for a non-null amazonSellerId never finds Amazon there.
Can I get Amazon Singapore price history?
Not from this API. Statistics, estimated sales and the ASIN converter cover 11 marketplaces and answer amazon.sg with a free 400 and no data. Store your own offers snapshots if you need a history.
Which category IDs work for amazon.sg bestsellers?
Only IDs from amazon.sg's own tree: 28 top-level slugs such as electronics, and numeric IDs below them, for example 6436074051. A numeric ID from another marketplace's tree gets a free 400 Invalid CategoryId.
Which delivery location does the API use for amazon.sg?
The default postcode 179431 when you send no geo_location. The featured offer can depend on the shopping location, so treat shipping and delivery figures as one reading, not every shopper's price.
Bottom line: use A19VAU5U5O7RUS for amazon.sg, expect SGD, recognise Amazon by sellerId, take category IDs from amazon.sg's own tree and keep history calls for the 11 covered stores. The offers endpoint page lists every field, and a free account includes 150 credits.