Home / Blog / Amazon Deals API: Lightning Deals, Savings and End Times as JSON

Amazon Deals API: Lightning Deals, Savings and End Times as JSON

Read Amazon's deals page as JSON: deal price, list price, savings percentage, start and end time and a lightning-deal flag for up to 50 deals per marketplace, optionally one department. How to poll it, spot new deals by dealId, alert before a deal ends, and what an empty list means.

September 20, 2026
5 min read
SellerMagnet Team
Share & Bookmark
Blueprint flow from a marketplace and department through the deals API to deduplicated deals and end-time alerts

To get Amazon deals as JSON, call the SellerMagnet /api/amazon-deals endpoint with a marketplace ID and, optionally, a department. One request returns up to 50 current deals with the deal price, the list price it is measured against, the savings percentage, start and end times and a lightning-deal flag. Poll it every few minutes, keep a set of the dealIds you have seen, and you have a deal feed that costs one credit per poll.

Key Takeaways

  • One request returns up to 50 deals (count, default 30) for one marketplace, optionally one department.
  • dealPrice.priceTotal and basisPrice are numbers in the marketplace currency; basisPrice is null when the page shows no list price.
  • dealStartTime and dealEndTime are ISO 8601 in UTC, so a countdown is one subtraction.
  • An empty deals list is real data (nothing on offer for that filter) and costs a credit; errors come back as 5xx.
  • dealId is the key for deduplication across polls; the same ASIN can be in several deals over time.

What does the deals API return?

The endpoint reads the marketplace's deals page and returns its deal collection as a list. Prices are in the marketplace currency (dealPrice.priceCurrency), times are UTC, and savings_percentage is taken from the deal badge or, when the badge shows none, computed from the two prices. coupon_savings carries the badge text when there is one, such as 20 % Rabatt on amazon.de.

One deal from /api/amazon-deals on amazon.de (example values)

{
  "success": true,
  "data": {
    "deals": [
      {
        "dealId": "5675cf93",
        "asin": "B094YCTK6P",
        "productTitle": "IceUnicorn Krabbelschuhe Baby Lauflernschuhe",
        "dealLink": "https://www.amazon.de/dp/B094YCTK6P",
        "dealPrice": {"priceTotal": 15.89, "priceCurrency": "EUR"},
        "basisPrice": 18.69,
        "savings_percentage": 15,
        "coupon_savings": null,
        "dealStartTime": "2025-07-08T04:15:00.000Z",
        "dealEndTime": "2025-07-08T16:15:00.000Z",
        "isLightningDeal": true,
        "image_url": "https://images-eu.ssl-images-amazon.com/images/I/717dw8J-hbL.jpg"
      }
    ]
  }
}
Fields of a deal object and their types.
FieldTypeMeaning
dealIdstringIdentifier of the deal - use it to deduplicate across polls
asinstringThe product on offer
dealPrice.priceTotalnumberDeal price in dealPrice.priceCurrency; 0.0 when the page price could not be read - skip those
basisPricenumber or nullList price the saving is measured against; null when the page shows none
savings_percentageinteger or nullFrom the deal badge, else computed from the two prices
coupon_savingsstring or nullBadge text as shown, e.g. 20 % Rabatt
dealStartTime / dealEndTimeISO 8601, UTCDeal window; N/A when the page gives none
isLightningDealbooleanTime-limited lightning deal. The endpoint does not return a claimed percentage or a Prime-exclusive flag
Blueprint table of the deal object fields with their types and meaning
Two prices, one currency: compare priceTotal with basisPrice and guard for null.

How do I monitor Amazon deals with Python?

Poll the endpoint, compare with the dealIds stored from the last poll, and report two things: deals that are new, and deals that end within the next two hours. The state lives in a small JSON file, so a cron job can run the script every 15 minutes without a database.

deal_watch.py - new deals and deals ending soon, one credit per run

import datetime as dt
import json
import os
import pathlib

import requests

API = "https://sellermagnet-api.com/api/amazon-deals"
STATE = pathlib.Path("deals_seen.json")
ENDING_SOON = dt.timedelta(hours=2)


def fetch_deals(marketplace_id: str, category_id: str | None = None, count: int = 50) -> list:
    params = {"marketplaceId": marketplace_id, "count": count,
              "api_key": os.environ["SELLERMAGNET_API_KEY"]}
    if category_id:
        params["category_id"] = category_id
    resp = requests.get(API, params=params, timeout=90)
    try:
        body = resp.json()
    except ValueError:  # e.g. an HTML error page from a proxy
        body = {}
    if resp.status_code != 200 or not body.get("success"):
        raise RuntimeError(f"{resp.status_code} {body.get('message')}")
    return body["data"]["deals"]


def ends_in(deal: dict) -> dt.timedelta | None:
    end = deal.get("dealEndTime")
    if not end or end == "N/A":
        return None
    return dt.datetime.fromisoformat(end.replace("Z", "+00:00")) - dt.datetime.now(dt.timezone.utc)


seen = set(json.loads(STATE.read_text())) if STATE.exists() else set()
deals = fetch_deals("A1PA6795UKMFR9", category_id="electronics")

for deal in deals:
    price = deal["dealPrice"]["priceTotal"]
    basis = deal.get("basisPrice")            # number, or null when the page shows no list price
    key = deal["dealId"] if deal.get("dealId") not in (None, "N/A") else deal["asin"]
    left = ends_in(deal)
    if price <= 0:
        continue                              # price could not be read on this poll
    if key not in seen:
        print(f"NEW  {deal['asin']} {price} {deal['dealPrice']['priceCurrency']}"
              f" (was {basis}, -{deal.get('savings_percentage')}%) {deal['productTitle'][:50]}")
    if left is not None and dt.timedelta(0) < left <= ENDING_SOON:
        print(f"ENDS {deal['asin']} in {int(left.total_seconds() // 60)} min")

STATE.write_text(json.dumps(sorted({d["dealId"] if d.get("dealId") not in (None, "N/A") else d["asin"]
                                    for d in deals})))

Why dealId and not asin

A product can be discounted again next week under a new deal, and one poll can hold the same ASIN twice with different deal windows. dealId names the offer; asin names the product. When the page shows no deal ID the field is N/A - the script falls back to the ASIN for those.

How do I filter deals by department?

Pass category_id with a department slug - the documented example is electronics; the top-level IDs in the category explorer are the candidates for other departments. Without it you get the marketplace's whole deal collection - lightning deals and the deal of the day alike. An unknown category_id is not rejected; it is passed to Amazon's deals filter as it is, so a typo simply returns fewer or no deals. count defaults to 30 and stops at 50; a higher value returns HTTP 400 Count Max: 50 after the credit is charged. geo_location (a postcode) is best-effort, as on search.

Deals ending within two hours, from the shell

curl -sG "https://sellermagnet-api.com/api/amazon-deals" \
  --data-urlencode "marketplaceId=A1PA6795UKMFR9" \
  --data-urlencode "category_id=electronics" \
  --data-urlencode "count=50" \
  --data-urlencode "api_key=$SELLERMAGNET_API_KEY" \
  | jq --arg now "$(date -u +%Y-%m-%dT%H:%M:%S)" \
       --arg limit "$(date -u -v+2H +%Y-%m-%dT%H:%M:%S 2>/dev/null || date -u -d '+2 hours' +%Y-%m-%dT%H:%M:%S)" \
       -r '.data.deals[] | select(.dealEndTime != "N/A" and .dealEndTime > $now and .dealEndTime <= $limit)
           | [.asin, .dealPrice.priceTotal, .savings_percentage, .dealEndTime] | @tsv'

What does an empty deals list mean?

An empty deals array with success: true means the deals page carried a deal collection with nothing in it for that filter - a niche department at a quiet hour - and it is billed like any other answer. A page that could not be read at all is not turned into an empty list: it returns HTTP 502 or 503, which the error-handling guide covers. Poll every 10 to 15 minutes: deal windows are hours long, and a lightning deal that appears and sells out inside one interval is not worth a credit a minute.

Blueprint sequence of a deals poll: cron triggers the script, the API returns deals, the script compares with stored IDs and sends alerts
Fifteen minutes, one credit, two kinds of alert.

To judge a deal, pair it with the product's recorded prices: the price history endpoint shows whether the deal price really is a low, and the bestsellers endpoint tells you how the product sells in its category.

Frequently Asked Questions

Is there an API for Amazon deals?

Yes. /api/amazon-deals returns up to 50 current deals of a marketplace as JSON, with deal price, list price, savings, start and end time and a lightning-deal flag.

Can I filter deals by category?

Yes. Pass category_id with a department slug such as electronics. Without it the whole deal collection of the marketplace is returned.

How do I know when a deal ends?

dealEndTime is an ISO 8601 timestamp in UTC. Subtract the current UTC time to get the remaining window; N/A means the page showed no end time.

Can basisPrice be missing?

Yes. It is null when the deal page shows no list price; savings_percentage then comes only from the deal badge, or is null too.

Does Amazon have an official deals API?

The Selling Partner API has none. The Product Advertising API exposes some deal pricing but needs an approved Associates account; this endpoint reads the public deals page instead.

Does an empty deals list cost a credit?

Yes. It is a real answer: the page held no deals for that filter. Read errors are returned as 5xx instead.

Bottom line: one credit per poll, deduplicate by dealId, parse the times as UTC and skip entries whose price could not be read. The deals endpoint page shows the full response, and a free account includes 500 credits - five days of 15-minute polling.

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.

500 free API credits • No credit card required • Cancel anytime