To tell a real Amazon price cut from a coupon-funded one, read both savings_percentage and coupon_savings from /api/amazon-deals. savings_percentage is the badge percentage (or one computed from dealPrice and basisPrice); coupon_savings is separate free-text badge, such as "15% off", that shows when a coupon is stacked on top. When coupon_savings states a plain percent, subtracting it from savings_percentage shows how much of the badge is the coupon and how much, if any, is left as a real cut to the shelf price.
Key Takeaways
- coupon_savings is badge text ("20 % Rabatt", "$5 off", "Clip coupon"), not a number - only a plain-percent badge can be checked against savings_percentage; everything else is unverifiable.
- A badge % at or below the coupon % means the coupon accounts for the whole stated saving: the shelf price did not move, and the saving disappears once the coupon runs out or is not clipped.
- There is no checkout-coupon field anywhere else in the API: offer data has no coupon or promotion field, so the deals endpoint is the only place this shows up at all.
- An empty deals list on one page is real, billed data, not proof there are zero deals platform-wide; a page with no deal data at all is a retryable 5xx.
- dealPrice.priceTotal of 0.0 means the page price could not be read - skip that deal rather than compute a percentage against it.
Why isn't the deals badge percentage enough on its own?
Because savings_percentage does not say whether a coupon is part of it. A deal can show "25% off" with a coupon_savings badge reading "15% off" stacked on the same listing: the price actually dropped by about 10 percentage points, and the other 15 only apply while the coupon is clipped. A deal showing the same 15% off with no separate price movement is a coupon with no real cut behind it at all - the shelf price is exactly what it was.
| Verdict | When | What it means |
|---|---|---|
| real-cut-plus-coupon | badge % is bigger than the parsed coupon % | a price cut beyond the coupon - worth it |
| coupon-covers-all | badge % is at or below the parsed coupon % | the coupon is the whole saving - shelf price is flat |
| coupon-only | a coupon badge, no separate savings_percentage | cannot cross-check; treat as coupon-only |
| coupon-unverifiable | a coupon badge without a plain percent (e.g. "$5 off") | cannot separate it from the price - flagged, not guessed |
| price-cut | savings_percentage with no coupon_savings badge | a plain reduction, no coupon involved |
How do I separate a coupon from a price cut in Python?
Pull the coupon percentage out of coupon_savings with a regex that only matches a plain percent ("15% off", "7,5 % Rabatt"); anything else - a dollar amount, a locale without a number, plain "Clip coupon" text - is reported as unverifiable instead of guessed at. Then classify() subtracts the coupon percent from the badge percent and clips the result at zero. get_with_retry() comes from retry.py, new_session() and ApiError from sellermagnet.py in the Python quickstart.
coupon_check.py - split the savings badge from the coupon badge
"""Classify whether an Amazon deal's advertised saving is a real price cut or coupon-funded.
Uses only the real sellermagnet.py / retry.py helpers (see the Python quickstart). Nothing here
calls the API directly - everything goes through get_with_retry.
"""
import re
from retry import get_with_retry
from sellermagnet import ApiError, new_session
# A coupon badge is free text ("20 % Rabatt", "Save 15%", "$5 off", "Clip coupon"), not a
# structured value (badge text or null). Only badges that
# state a plain percent can be checked against savings_percentage; everything else is reported
# as present-but-unverifiable rather than guessed at.
_PERCENT = re.compile(r"(\d+(?:[.,]\d+)?)\s*%")
def parse_coupon_percent(text):
if not text:
return None
m = _PERCENT.search(text)
return float(m.group(1).replace(",", ".")) if m else None
def classify(deal: dict) -> dict:
"""One /amazon-deals entry -> a verdict dict. Never raises on odd data; reports it instead."""
asin = deal.get("asin", "N/A")
price_total = (deal.get("dealPrice") or {}).get("priceTotal")
badge_pct = deal.get("savings_percentage")
coupon_text = deal.get("coupon_savings")
if not isinstance(price_total, (int, float)) or price_total <= 0:
return {"asin": asin, "verdict": "unreadable", "note": "priceTotal missing or 0.0 (page price unreadable)"}
coupon_pct = parse_coupon_percent(coupon_text)
if coupon_text is None:
if badge_pct is None:
return {"asin": asin, "verdict": "no-saving-shown", "note": "no coupon, no savings badge, no basisPrice"}
return {"asin": asin, "verdict": "price-cut", "note": f"{badge_pct}% off, no coupon involved",
"badge_pct": badge_pct}
if coupon_pct is None:
return {"asin": asin, "verdict": "coupon-unverifiable",
"note": f"coupon badge '{coupon_text}' is not a plain percent - cannot separate it from the price",
"badge_pct": badge_pct}
if badge_pct is None:
return {"asin": asin, "verdict": "coupon-only",
"note": f"{coupon_pct}% coupon, no separate price-reduction badge to check it against",
"coupon_pct": coupon_pct}
real_cut = round(badge_pct - coupon_pct, 1)
if real_cut <= 0:
return {"asin": asin, "verdict": "coupon-covers-all",
"note": f"badge shows {badge_pct}% but the {coupon_pct}% coupon already accounts for all of it "
"- the shelf price did not drop",
"badge_pct": badge_pct, "coupon_pct": coupon_pct, "real_cut_pct": 0.0}
return {"asin": asin, "verdict": "real-cut-plus-coupon",
"note": f"~{real_cut}% price cut beyond the {coupon_pct}% coupon",
"badge_pct": badge_pct, "coupon_pct": coupon_pct, "real_cut_pct": real_cut}
def scan_deals(session, marketplace_id: str, category_id: str = None, count: int = 50) -> list:
params = {"marketplaceId": marketplace_id, "count": count}
if category_id:
params["category_id"] = category_id
data = get_with_retry(session, "amazon-deals", **params)
seen, rows = set(), []
for deal in data["deals"]: # an empty list here is real, billed data
deal_id = deal.get("dealId", "N/A")
if deal_id != "N/A" and deal_id in seen: # the same page can repeat a dealId
continue
seen.add(deal_id)
rows.append(classify(deal))
return rows
_ORDER = ["real-cut-plus-coupon", "price-cut", "coupon-covers-all", "coupon-only",
"coupon-unverifiable", "no-saving-shown", "unreadable"]
def report(rows: list) -> None:
buckets = {}
for row in rows:
buckets.setdefault(row["verdict"], []).append(row)
for verdict in _ORDER:
if verdict not in buckets:
continue
print(f"{verdict} ({len(buckets[verdict])}):")
for row in buckets[verdict]:
print(f" {row['asin']}: {row['note']}")
if __name__ == "__main__":
session = new_session()
try:
rows = scan_deals(session, "ATVPDKIKX0DER", category_id="electronics")
except ApiError as err:
print(f"deals call failed: {err.status} {err}")
else:
report(rows)
One deal from /api/amazon-deals (trimmed, illustrative values)
{
"success": true,
"data": {
"deals": [
{
"dealId": "d2", "asin": "B0D3K7Z9QH",
"dealPrice": {"priceTotal": 44.99, "priceCurrency": "USD"},
"basisPrice": 59.99,
"savings_percentage": 25,
"coupon_savings": "15% off",
"dealStartTime": "2026-11-11T08:00:00.000Z",
"dealEndTime": "2026-11-12T20:00:00.000Z",
"isLightningDeal": true
}
]
}
}
Output (illustrative deals)
real-cut-plus-coupon (1):
B0D3K7Z9QH: ~10.0% price cut beyond the 15.0% coupon
price-cut (1):
B0CL61F39H: 22% off, no coupon involved
coupon-covers-all (1):
B0F1N2M3L4: badge shows 15% but the 15.0% coupon already accounts for all of it - the shelf price did not drop
coupon-unverifiable (1):
B0G5H6J7K8: coupon badge '$3 off' is not a plain percent - cannot separate it from the price

What does the coupon_savings field actually contain?
Whatever text Amazon's deal badge shows, in the page's own language: "15% off" on amazon.com, \"20 % Rabatt\" on amazon.de, a dollar or euro amount, or just a label with no number at all (badge text or null, by design - not a structured value). There is no separate structured coupon amount anywhere in the API - the offers endpoint has no coupon or promotion field either, so a checkout price with the coupon applied is never directly visible. Only a badge that states a plain percent can be checked against savings_percentage; a dollar-amount or wordless badge is reported as coupon-unverifiable rather than converted with an assumed price.

Don't convert a dollar-off coupon yourself
A badge like "$5 off" needs the item's own price to turn into a percentage, and the deals response does not confirm the coupon was applied before or after dealPrice.priceTotal was read. Report it as unverifiable rather than compute a percentage that could be wrong either way. Even a plain-percent coupon badge carries the same unstated assumption: the script treats the coupon percent and the savings-badge percent as measured off the same base price and applied one after the other, which the API response does not actually confirm either - treat real_cut_pct as an estimate, not an exact figure.
What does this mean for a reseller watching deals?
A deal in coupon-covers-all is not a lower shelf price: if the plan is to resell at the deal price, the coupon has to be clipped (or applied automatically) on every unit bought, and the price reverts the moment the coupon ends. A deal in real-cut-plus-coupon keeps part of its saving even without the coupon. The deals API guide covers polling and department filters, and the deal price history check adds a Buy Box history check for the badge percentage itself, which this script takes as given.
Frequently Asked Questions
Does coupon_savings say how many dollars or percent the coupon is worth?
Only as free badge text, in the page's own language. A plain percent can be parsed; a dollar amount or wordless badge cannot be converted safely and is reported as unverifiable.
If a deal has no coupon_savings badge, is the savings_percentage a real cut?
It means no coupon is stacked on the deal, so the badge is not coupon-funded - but it can still be checked against Buy Box price history separately.
Can coupon_savings appear without a savings_percentage badge?
Yes. That deal has only the coupon to go on; there is no separate price-reduction badge to subtract it from, so it is reported as coupon-only.
Is there a checkout-level coupon field in the SellerMagnet API?
No. Offer data has no coupon or promotion field, so a coupon-adjusted checkout price is never directly visible anywhere in the API.
What happens when the badge percent is smaller than the coupon percent?
The script clips the real cut at zero and reports coupon-covers-all: the coupon accounts for all or more of the stated saving, so the shelf price has not actually dropped.
Bottom line: read both badges, parse only a plain-percent coupon, subtract it from the savings badge, and flag anything you cannot verify instead of guessing. One /amazon-deals poll covers up to 50 deals for one credit; a free account includes 150 credits, enough for three full pages before deciding which deals are worth the clip.