ASINSpotlight

Scraping API Documentation

Complete API reference for the ASINSpotlight Amazon Scraping API

Base URL

https://api.asinspotlight.com/v1

Authentication

All requests require an API key passed in the x-api-key header:

curl -H "x-api-key: YOUR_API_KEY" "https://api.asinspotlight.com/v1/product?asin=B0B3ZD8QXJ"
Header Required Description
x-api-key Yes Your API key

Response Metadata

Every successful response carries a meta object with per-request metadata. The meta.usage block lets you drive quota-aware loops without polling a separate endpoint:

"meta": {
  "marketplace": "us",
  "language": "en",
  "timing_ms": 1842,
  "request_url": "https://api.asinspotlight.com/v1/product?asin=B0B3ZD8QXJ&marketplace=us",
  "timestamp": "2026-05-03T10:14:22.318Z",
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "usage": { "requests_consumed": 1, "requests_remaining": 49999 }
}

requests_consumed is 1 for any successful scrape (HTTP 200) — including not-found results where found is false, since the page was still fetched and parsed; 0 for any failure. meta.usage is also included on 429 rate-limit and quota-exceeded errors so you can read remaining credits even when a request is rejected.

Found vs. Not Found

Status codes reflect our service health, not what's on Amazon. Every successful response carries a top-level found boolean:

  • found: true — the entity was found; data holds the payload.
  • found: false — the scrape succeeded but the entity isn't on Amazon (invalid ASIN/seller, removed listing). data is null, the HTTP status is still 200, and the request still counts as one credit.

Branch on found, not on the HTTP status, to tell "found" from "not found". Reserve 4xx for your request errors and 5xx for our failures.

Display Language

Every endpoint accepts an optional language parameter:

Value Behavior
en The English render of the page (default)
native The marketplace's own language (currently supported: it, fr, de, es, more coming)

With language=native, free-text fields (title, category and brand names, condition_text, delivery text) come back in the marketplace's language, while normalized fields (condition slugs, prices, dates, units) stay canonical, so condition filters and your parsing keep working unchanged. The requested language is echoed in meta.language.

Requesting native on a marketplace without native support returns HTTP 400 with error code NATIVE_LANGUAGE_NOT_SUPPORTED and is not billed.

Example (Italian product page in Italian)

curl -H "x-api-key: YOUR_API_KEY" \
  "https://api.asinspotlight.com/v1/product?asin=B0BWSCJ13H&marketplace=it&language=native"

Deals and Promotions

Product data and list-page entries carry a promotion object describing the discount state of the offer: the deal badge Amazon renders only while a promotion is live, and the struck-through reference prices the discount is measured against. One fetch answers "is this product on a deal right now, and how deep is the cut?", with no price history required.

promotion appears on /v1/product data and on every shallow_parts[] entry of list pages (search, category, bestseller). It is null when the page shows neither a deal badge nor a struck-through price, which simply means the product is selling at its normal price.

"promotion": {
  "deal": {
    "kind": "limited_time",
    "label": "Limited time deal",
    "deal_id": "amzn1.deal.b12c9bd2",
    "ends_at": "2026-08-16T04:00:00Z",
    "ends_on": "2026-08-16",
    "ends_in_days": 15,
    "ends_on_text": null
  },
  "list_price": {
    "amount": 199.99,
    "label": "List Price:",
    "savings_amount": 50.99,
    "savings_percent": 25.0
  },
  "lowest_price_30_days": null
}

The three parts are independent: an everyday markdown can be struck through against a list price with no badge at all, and a badged deal does not have to carry a reference price.

The deal badge

Presence is the signal: Amazon renders the badge only while the deal is running, so a non-null deal means the promotion is live at fetch time, and null means it is not. That makes "has the promotion ended?" answerable from a single request instead of a price time series.

Field Description
kind Normalized deal type: limited_time, lightning, or prime_exclusive. null when the badge wording names no mechanic (countdown badges, seasonal badges like "Black Friday Deal", unrecognized locales); the raw wording is still in label
label Verbatim badge text as rendered, in the page's language ("Limited time deal", "Oferta flash")
deal_id Amazon's own promotion ID (amzn1.deal.…), stable for the lifetime of one deal and shared across the ASINs it covers. Compare it across scrapes to tell a continuing deal from a new one at a similar price. null on list-page entries
ends_at The exact moment the deal expires, ISO 8601 in UTC (2026-08-16T04:00:00Z). Read from Amazon's machine-readable timestamp, so it is locale-independent; prefer it for anything time-sensitive
ends_on The calendar day the deal ends, ISO YYYY-MM-DD: the UTC day of ends_at, or the day named in Amazon's deal-terms popover when the page carries no timestamp. A day-granularity summary, not a purchase deadline
ends_in_days Whole days from the scrape date to ends_on; 0 means the deal ends today. null on list-page entries (derive it from ends_at there)
ends_on_text Amazon's own end-date sentence, verbatim ("Questa offerta termina il 26 luglio 2026"). Absent on storefronts that render no deal-terms popover (amazon.com is one)

Reference prices

list_price and lowest_price_30_days share one shape:

Field Description
amount The struck-through price
label Verbatim label Amazon rendered ("List Price:", "Typical:", "Prezzo consigliato:"). null when the struck price carries no label
savings_amount amount minus the current price. Never negative: a reference at or below the current price is not a discount, so the field is null rather than zero or negative
savings_percent The discount as a positive whole percent. Amazon's own rendered figure when it shows one (that is what the shopper sees), otherwise derived and rounded the way Amazon rounds

list_price is the headline struck-through price. Usually that is the manufacturer's list price, but Amazon fills the same slot with a typical, median, or former price when it has no list price to show ("Typical:", "Prezzo mediano:", "Ancien prix :"); the label wording is the only thing that states which one you got. lowest_price_30_days is the lowest price of the last 30 days, which EU storefronts must display alongside a discount (the Omnibus Directive); it is absent outside the EU.

On list pages. A search, category, or bestseller entry is a summary tile, so its promotion is the shallow half of what a product page reports: the deal is named (kind, label) and the struck-through price is present, but there is no deal_id and no ends_on_text, ends_at appears only for countdown badges (which state their own target), and ends_in_days is always null. Call /v1/product on the ASIN when you need the deal's identity or exact deadline.

Coupons are separate. A clip-to-apply coupon is a different discount mechanism and stays in its own coupon field ({"unit": "percent", "value": 15} or {"unit": "currency", "value": 5}), on both product data and list-page entries, and it means the same thing in both places: value is what the coupon takes off, never the price left after it. A percent coupon carries the percentage, a currency coupon the amount in the marketplace's local currency. Coupons are not reflected in price, so the net price is yours to compute. A listing can carry a coupon and a deal at the same time.

Endpoints

GET /v1/product

Retrieve product details by ASIN.

Parameters

Parameter Type Required Default Description
asin string Yes Amazon product ASIN (10-character pattern ^[A-Z0-9]{10}$)
marketplace string No us Marketplace code (see below)
language string No en en or native (see Display Language)

Example

curl -H "x-api-key: YOUR_API_KEY" \
  "https://api.asinspotlight.com/v1/product?asin=B0B3ZD8QXJ&marketplace=us"

Response

{
  "success": true,
  "found": true,
  "page_type": "product",
  "data": {
    "asin": "B0B3ZD8QXJ",
    "title": "Product Title",
    "buybox": true,
    "bb_price": 29.99,
    "rating": 4.5,
    "reviews": 1234,
    "bsr": 5678,
    "in_stock": true,
    "is_prime": true,
    "promotion": {
      "deal": {
        "kind": "limited_time",
        "label": "Limited time deal",
        "deal_id": "amzn1.deal.b12c9bd2",
        "ends_at": "2026-08-16T04:00:00Z",
        "ends_on": "2026-08-16",
        "ends_in_days": 15,
        "ends_on_text": null
      },
      "list_price": {
        "amount": 39.99,
        "label": "List Price:",
        "savings_amount": 10.00,
        "savings_percent": 25.0
      },
      "lowest_price_30_days": null
    },
    "brand": { "name": "BrandName", "url": "/stores/BrandName" },
    "category": { "name": "Electronics", "url": "/b?node=123" },
    "image_url": "https://m.media-amazon.com/images/I/...",
    "sellers_all": 5,
    "bought_past_month": 1000
  },
  "meta": {
    "marketplace": "us",
    "timing_ms": 2340,
    "request_url": "https://api.asinspotlight.com/v1/product?asin=B0B3ZD8QXJ&marketplace=us",
    "timestamp": "2026-04-03T12:00:00.000Z",
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "usage": { "requests_consumed": 1, "requests_remaining": 49999 }
  }
}

bought_past_month is coerced from Amazon's Xk+ bought in past month label to an integer (e.g. 2K+2000).

promotion reports whether the offer is on a live deal and the struck-through prices the discount is measured against; null means the product is selling at its normal price. See Deals and Promotions.


GET /v1/offers

Retrieve every seller offer for a product — the full Buy Box panel and All Offers Display — with each offer's condition, price, shipping, fulfillment method, seller rating, and stock.

Parameters

Parameter Type Required Default Description
asin string Yes Amazon product ASIN
marketplace string No us Marketplace code
condition string No all Filter offers by condition (see below)
language string No en en or native (see Display Language)

Filtering by condition

By default (condition=all) offers of every condition are returned. Pass condition to narrow the result to a single condition or used tier:

Value Returns
all All conditions (default)
new New offers only
used Any used tier (Like New / Very Good / Good / Acceptable)
used_like_new Used – Like New only
used_very_good Used – Very Good only
used_good Used – Good only
used_acceptable Used – Acceptable only
collectible Collectible offers only

The filter is applied to each offer's resolved condition, so the response contains only offers of the requested condition, and fba_count / fbm_count / sold_by_amazon reflect the filtered set. Each request counts as one credit regardless of the filter.

Example

curl -H "x-api-key: YOUR_API_KEY" \
  "https://api.asinspotlight.com/v1/offers?asin=B0B3ZD8QXJ&marketplace=us"

Example (used offers only)

curl -H "x-api-key: YOUR_API_KEY" \
  "https://api.asinspotlight.com/v1/offers?asin=B0B3ZD8QXJ&marketplace=us&condition=used"

Response

Each entry in product_sellers_info carries a normalized condition (new, used_like_new, used_very_good, used_good, used_acceptable, or collectible) and the verbatim condition_text heading Amazon shows for that offer. condition is null when Amazon's heading is absent or not recognized (e.g. Renewed/Refurbished, or some non-English wordings) — the raw label is still available in condition_text. seller_id is null for offers sold directly by Amazon.

The featured (Buy Box) offer is flagged with is_pinned. At most one offer per response carries it, so you can read the Buy Box winner directly instead of inferring it from price. Position in the array is not a substitute: a response can list many offers and still have no pinned one, which means Amazon rendered no featured offer for that ASIN. A condition filter can also drop the pinned offer, because Amazon returns the featured offer whatever condition you ask for.

Each offer carries a delivery array with the promises Amazon displayed. kind is standard for the primary slot and fastest for the secondary one, which Amazon also uses for Prime upsells, so read it as "the other option shown" rather than a guaranteed faster one. date_min / date_max give the promised window as absolute dates, and days_min / days_max express the same promise in whole days from the request date, where 0 means delivery today. When a promise cannot be resolved to a date, every date and day field is null rather than a placeholder number, so treat null as unknown. Use is_free rather than shipping_price to tell free delivery apart from a cost we could not read. text is Amazon's wording verbatim and can embed a live countdown, so avoid using it as a cache key.

{
  "success": true,
  "found": true,
  "page_type": "offers",
  "data": {
    "sold_by_amazon": true,
    "fba_count": 3,
    "fbm_count": 2,
    "product_sellers_info": [
      {
        "name": "Amazon.com",
        "price": 29.99,
        "shipping_price": 0,
        "is_fba": true,
        "is_amazon": true,
        "stock_qty": 100,
        "rating_percent": 95,
        "reviews_count": 50000,
        "condition": "new",
        "condition_text": "New",
        "seller_id": null,
        "domain": "com",
        "is_just_launched": false,
        "is_pinned": true,
        "delivery": [
          {
            "kind": "standard",
            "days_min": 8,
            "days_max": 8,
            "date_min": "2026-07-25",
            "date_max": "2026-07-25",
            "is_free": true,
            "text": "FREE delivery Saturday, July 25."
          },
          {
            "kind": "fastest",
            "days_min": 5,
            "days_max": 7,
            "date_min": "2026-07-22",
            "date_max": "2026-07-24",
            "is_free": null,
            "text": "Or fastest delivery July 22 - 24."
          }
        ]
      },
      {
        "name": "ThriftBooks",
        "price": 18.50,
        "shipping_price": 3.99,
        "is_fba": false,
        "is_amazon": false,
        "stock_qty": 5,
        "rating_percent": 97,
        "reviews_count": 4200,
        "condition": "used_like_new",
        "condition_text": "Used - Like New",
        "seller_id": "A3XYZ123456",
        "domain": "com",
        "is_just_launched": false,
        "is_pinned": false,
        "delivery": [
          {
            "kind": "standard",
            "days_min": 6,
            "days_max": 11,
            "date_min": "2026-07-23",
            "date_max": "2026-07-28",
            "is_free": false,
            "text": "$3.99 delivery July 23 - 28."
          }
        ]
      }
    ]
  },
  "meta": { "..." : "..." }
}

Search products by keyword.

Parameters

Parameter Type Required Default Description
keyword string Yes Search keyword. URL-encode multi-word queries (e.g. wireless+headphones)
marketplace string No us Marketplace code
page integer No 1 Page number to retrieve (1-based). Amazon usually caps a keyword search at 20 pages
language string No en en or native (see Display Language)

Pagination

Pass page=N to fetch deeper pages of the same query. The response's data.current_page and data.last_page_number tell you where you are and how many pages Amazon exposes for that query. Each paginated request counts as one credit.

Amazon serves one of two result-page layouts, chosen per query, and they pair with different pagination walls: up to 48 entries per page stopping at 7 pages, or up to 16 entries per page stopping at 20. Both reach roughly the same depth overall. Read shallow_parts.length and data.last_page_number from the response rather than assuming fixed values, and don't page past last_page_number: total_results_count reports the whole match set (often tens of thousands), not what Amazon will actually paginate through.

Example

curl -H "x-api-key: YOUR_API_KEY" \
  "https://api.asinspotlight.com/v1/search?keyword=wireless+headphones&marketplace=us"

Example (page 2)

curl -H "x-api-key: YOUR_API_KEY" \
  "https://api.asinspotlight.com/v1/search?keyword=wireless+headphones&marketplace=us&page=2"

Response

{
  "success": true,
  "found": true,
  "page_type": "search",
  "data": {
    "title": "wireless headphones",
    "current_page": 1,
    "last_page_number": 20,
    "total_results_count": 10000,
    "shallow_parts": [
      {
        "asin": "B0CQXMXJC5",
        "title": "Soundcore Q20i Headphones",
        "index_on_page": 1,
        "page_number": 1,
        "price": 39.99,
        "shipping": 0,
        "is_prime": true,
        "rating": 4.6,
        "reviews": 58800,
        "bought_past_month": 20000,
        "in_stock": true,
        "coupon": null,
        "image_url": "https://m.media-amazon.com/images/I/...",
        "promotion": {
          "deal": {
            "kind": "limited_time",
            "label": "Limited time deal",
            "deal_id": null,
            "ends_at": null,
            "ends_on": null,
            "ends_in_days": null,
            "ends_on_text": null
          },
          "list_price": {
            "amount": 49.99,
            "label": "List:",
            "savings_amount": 10.00,
            "savings_percent": 20.0
          },
          "lowest_price_30_days": null
        },
        "has_variation_swatches": true,
        "advertised_variation_count": 4,
        "sampled_variation_asins": ["B0CQXMABC1", "B0CQXMABC2", "B0CQXMABC3"]
      }
    ]
  },
  "meta": { "..." : "..." }
}

index_on_page and page_number place each entry in Amazon's own ranking, so merged pages stay ordered. shipping is the shipping cost the tile quotes, in the marketplace's local currency, and 0 means free shipping. is_prime is true when the tile carries the Prime badge and null when it does not. coupon holds any clip-to-apply coupon the tile advertises, in the shape described in Deals and Promotions, and is null on most listings.

Each list item also carries three best-effort variation signals from the result tile's color/size swatches: has_variation_swatches is true when the tile shows a swatch row — a positive-only signal that the product is one child of a variation family (false means there was no swatch row, not a guarantee the product has no variations); advertised_variation_count is the family size the tile advertises (visible swatches plus the +N more overflow), or null when there is no swatch row; and sampled_variation_asins lists the sibling child ASINs Amazon rendered as swatches — a partial set (typically ≤6 for large families, excluding the item's own ASIN), not the full family. The same three fields appear on shallow_parts[] for every list page (search, category, bestseller).

Each entry also carries the tile's promotion (deal badge and struck-through reference price) in the shallow list-page shape described in Deals and Promotions: no deal_id, ends_at only for countdown badges, ends_in_days always null. Like the variation signals, it appears on shallow_parts[] for every list page.


GET /v1/seller

Retrieve a seller storefront profile by seller ID.

Parameters

Parameter Type Required Default Description
sellerId string Yes Amazon seller (merchant) ID — the A… token from a storefront URL (/sp?seller=<sellerId>)
marketplace string No us Marketplace code
language string No en en or native (see Display Language)

Example

curl -H "x-api-key: YOUR_API_KEY" \
  "https://api.asinspotlight.com/v1/seller?sellerId=A1PXYTJNWCR133&marketplace=us"

Response

Returns the seller name, feedback rating and positive-feedback percentage over the last 12 months, total rating count, the storefront link, and the Detailed Seller Information block (legal business name and address) when Amazon publishes it. An invalid seller ID returns 200 with found: false and data: null.

{
  "success": true,
  "found": true,
  "page_type": "seller",
  "data": {
    "seller_id": "A1PXYTJNWCR133",
    "name": "Lovinio",
    "storefront_url": "/s?ie=UTF8&marketplaceID=ATVPDKIKX0DER&me=A1PXYTJNWCR133",
    "rating": 3.4,
    "positive_percent": 59,
    "ratings_count": 217,
    "business_name": "Lovinio Inc",
    "business_address": ["4652 Eagle Falls Pl", "Tampa", "FL", "33619", "US"]
  },
  "meta": { "..." : "..." }
}

POST /v1/scrape

Scrape any Amazon URL. The page type is auto-detected.

Body (JSON)

Field Type Required Default Description
url string Yes Full Amazon URL
marketplace string No us Marketplace code
language string No en en or native (see Display Language)

Example

curl -X POST -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.amazon.com/s?k=laptop+stand", "marketplace": "us"}' \
  "https://api.asinspotlight.com/v1/scrape"

Response

The data shape matches the detected page_type. For product, search, offers, and seller it matches the typed-endpoint payloads above. category, bestseller, storefront, and reviews return a structured payload tailored to the page. A not-found page returns found: false and data: null.

{
  "success": true,
  "found": true,
  "page_type": "search",
  "data": { "...": "..." },
  "meta": { "...": "..." }
}

Supported Marketplaces

Code Country Domain
us United States amazon.com
uk United Kingdom amazon.co.uk
de Germany amazon.de
fr France amazon.fr
it Italy amazon.it
es Spain amazon.es
ca Canada amazon.ca
au Australia amazon.com.au
jp Japan amazon.co.jp
in India amazon.in
mx Mexico amazon.com.mx
br Brazil amazon.com.br
tr Turkey amazon.com.tr
sa Saudi Arabia amazon.sa
ae UAE amazon.ae
sg Singapore amazon.sg
nl Netherlands amazon.nl
pl Poland amazon.pl
se Sweden amazon.se
be Belgium amazon.com.be

Error Responses

All errors follow a consistent format:

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description"
  }
}

429 rate-limit and quota responses also include a top-level meta.usage block so you can read remaining credits even when the request is rejected.

A missing entity (invalid ASIN/seller, removed listing) is not an error — it returns 200 with found: false and data: null, and counts as one credit. See Found vs. Not Found.

HTTP Status Code Description
400 validation Missing required parameter, invalid marketplace or language code, or unrecognized field. Returned by the framework's validation pipe; payload shape may differ from the standard error envelope.
400 NATIVE_LANGUAGE_NOT_SUPPORTED language=native requested on a marketplace without native support (see Display Language). Not billed
401 MISSING_API_KEY No x-api-key header provided
401 INVALID_API_KEY API key is not valid
429 RATE_LIMIT_EXCEEDED Too many parallel in-flight requests for your API key
429 MONTHLY_QUOTA_EXCEEDED No active API request credits available
500 SCRAPE_FAILED Parser reached the page but could not extract structured data
500 INTERNAL_ERROR Internal service failure or transport error to the parser worker
503 CAPTCHA_DETECTED Amazon returned a captcha page. Retry after a short delay
503 API_USAGE_UNAVAILABLE Usage tracking is temporarily unavailable. Retry after a short delay