Getting Amazon and Walmart product data in one API call eliminates the need to maintain separate scrapers or pay for two specialized APIs. The 2026 ecommerce data API landscape has consolidated: you either use platform-specific APIs (Amazon PA-API, Walmart Affiliate API) or a multi-platform search API that covers both.
The part that decides your bill is not the headline price per request. It is which domains you need, how many credits each one burns, and how many of those calls come back with usable data. That varies enough per retailer that a provider who is cheapest on Amazon can be the wrong choice the moment you add a third site.
Platform-Specific APIs
Amazon Product Advertising API (PA-API 5.0): requires an Amazon Associates account, returns product data only for items you link to, rate limited to 1 request/second without prior sales. Walmart Affiliate API: requires approval, returns product data with pricing, limited to Walmart.com inventory. Both require separate integrations, separate auth, and separate rate limit handling.
Multi-Platform Search API
A single API key that returns structured product data from both Amazon and Walmart. One auth scheme, one envelope, one rate limit to manage. The tradeoff: you get search result data (titles, prices, ratings, URLs) rather than full catalog data (inventory levels, BSR history, variant details).
Each retailer has its own path. There is no generic platform parameter to switch on:
import os
import requests
BASE = "https://api.scavio.dev/api/v1"
H = {"Authorization": f"Bearer {os.environ['SCAVIO_API_KEY']}"}
def search(platform, query):
r = requests.post(f"{BASE}/{platform}/search", headers=H,
json={"query": query}, timeout=60)
r.raise_for_status()
return r.json()
amazon = search("amazon", "wireless mouse")
walmart = search("walmart", "wireless mouse")
print(amazon["credits_used"], amazon["data"]["count"]) # 1 16
print(walmart["credits_used"], walmart["data"]["count"]) # 1 62Every response is wrapped in the same envelope: data, response_time, credits_used, credits_remaining. The last two matter more than they look, and the benchmarking section below leans on them.
The Response Shapes Are Not Identical
One API key does not mean one schema. Amazon and Walmart products come back with different field names for the same concepts, because each is parsed from a different source page rather than remapped onto a lowest-common-denominator model.
| Concept | Amazon | Walmart |
|---|---|---|
| Product identifier | asin | id |
| Result position | position | pos |
| Review count | reviews_count | rating_count |
| Paid placement | is_sponsored | sponsored |
| Stock state | (not returned) | out_of_stock, availability_status |
| Seller | (not returned) | seller_name, seller_id |
| Fulfillment | delivery | fulfillment object |
This is a real wart, not a design feature. Plan for it instead of discovering it in production: normalize at your boundary, the first time you touch a response, and keep your own product model in the middle.
def normalize(platform, item):
if platform == "amazon":
return {
"sku": item["asin"],
"title": item["title"],
"price": item.get("price"),
"rating": item.get("rating"),
"reviews": item.get("reviews_count"),
"sponsored": item.get("is_sponsored", False),
"rank": item.get("position"),
"in_stock": None,
}
return {
"sku": item["id"],
"title": item["title"],
"price": item.get("price"),
"rating": item.get("rating"),
"reviews": item.get("rating_count"),
"sponsored": item.get("sponsored", False),
"rank": item.get("pos"),
"in_stock": not item.get("out_of_stock", False),
}
rows = ([normalize("amazon", p) for p in amazon["data"]["products"]]
+ [normalize("walmart", p) for p in walmart["data"]["products"]])Do this and swapping a vendor later is a day of work in one function, not a rewrite of everything downstream. Skip it and every report, join, and dashboard you build inherits two vocabularies.
Note the asymmetry in what is available at all. Walmart search returns seller identity and stock state; Amazon search does not. If your product depends on knowing who is selling an item, that constraint decides your architecture regardless of which vendor you pick.
What a Call Actually Costs, by Domain
Advertised per-request pricing hides the thing that actually moves your bill: some domains only respond to expensive infrastructure. A datacenter proxy is cheap. A headless browser costs more. Residential proxies cost more again. When a retailer refuses everything but the expensive path, that is the price of that retailer, whatever the pricing page says.
Scavio prices this by formula rather than per endpoint: credits are ceil(upstream cost / 5), floor of 1. Measured against production:
| Target | Path required | Credits per call |
|---|---|---|
| Amazon (all endpoints) | datacenter | 1 |
| Walmart US and Canada | datacenter | 1 |
| Walmart Mexico | residential only | 2 |
Arbitrary URL, normal tier | datacenter | 1 |
Arbitrary URL, advanced tier | headless browser | 1 |
Arbitrary URL, ultra tier | residential | 2 |
Walmart Mexico is the instructive row. It is the same retailer and the same parser as Walmart US, but walmart.com.mx refuses the datacenter pool outright, so every call has to take the expensive route and costs double. Nothing about "Walmart support" on a feature matrix tells you that. Only running your own URLs does.
Benchmark Before You Commit
The common question when evaluating vendors across a mixed basket of retailers is how to compare them without burning a month of credits first. You do not need a month. You need about fifty calls and the discipline to measure cost per successful response rather than cost per request.
Success rate is the term everyone omits. A provider at half the price with a 70% hit rate on your worst domain is more expensive than the one that costs double and always works, and the pricing page will never tell you which you bought.
Because credits_used ships on every response, you can total real spend during a trial instead of estimating it:
from collections import defaultdict
def bench(basket, runs=5):
"""basket: list of (platform, query). Returns cost per successful call."""
stats = defaultdict(lambda: {"credits": 0, "ok": 0, "fail": 0})
for platform, query in basket:
for _ in range(runs):
s = stats[platform]
try:
r = requests.post(f"{BASE}/{platform}/search", headers=H,
json={"query": query}, timeout=60)
body = r.json()
except requests.RequestException:
s["fail"] += 1
continue
# Billed calls report credits even when the payload is thin.
s["credits"] += body.get("credits_used", 0)
if r.ok and body.get("data", {}).get("products"):
s["ok"] += 1
else:
s["fail"] += 1
for platform, s in stats.items():
total = s["ok"] + s["fail"]
cps = s["credits"] / s["ok"] if s["ok"] else float("inf")
print(f"{platform:10s} success {s['ok']}/{total} "
f"credits {s['credits']} per-success {cps:.2f}")
return stats
bench([("amazon", "wireless mouse"), ("walmart", "wireless mouse")])Run that against the retailers you actually need, not a vendor's demo query. Two rules make the result honest:
Use your real URLs and your real queries. Long-tail retailers behave nothing like Amazon, and a benchmark built from popular search terms flatters every provider equally.
Count a thin 200 as a failure. This is the trap that makes cheap providers look good. A response that returns HTTP 200 with an empty product array is still a billed call, and if you only count non-2xx as errors you will measure a 100% success rate on a domain that never returned data. The check above requires a non-empty products array before it counts a call as a success.
When a Domain Refuses the Cheap Path
Long-tail retailers are where the per-domain variance bites, and they fail differently than the big two. Calling /api/v1/extract on a REI product page at the default normal tier returns:
{
"error": "This domain requires super=true. Please add super=true parameter to your request."
}That message is wrong, and it is our bug: super=true is an upstream proxy parameter that is not part of the public API and does nothing if you send it. The fix is to raise the tier:
r = requests.post(f"{BASE}/extract", headers=H, timeout=120, json={
"url": "https://www.rei.com/product/224638/...",
"format": "markdown",
"mode": "ultra",
})At ultra the same page returns 82,122 characters of markdown, and takes about 29 seconds against roughly 2 seconds for an Amazon search. So that one long-tail retailer costs double the credits and an order of magnitude more wall-clock time than the marketplace endpoints. Budget for latency as well as credits when a long-tail site joins your basket, and time out generously.
The broader point: assume every new domain you add is expensive until a measurement says otherwise. If you are sizing an Amazon-heavy workload specifically, the best Amazon product data APIs breakdown covers per-endpoint differences, and the Walmart data API comparison does the same for Walmart.
Use Cases That Need Both Platforms
Dropshipping arbitrage: find products cheaper on Walmart, sell on Amazon. Competitive pricing: monitor your product on both marketplaces. Market research: compare product selection and pricing across platforms. Price monitoring SaaS: track prices for clients across all major retailers. For the seller-side view of that last one, see Walmart seller product research.
Building a Price Tracker
With normalization in place, the tracker stays short and the storage layer never learns which retailer a row came from:
import json
from datetime import datetime, timezone
def snapshot(queries, platforms=("amazon", "walmart")):
out = {"date": datetime.now(timezone.utc).strftime("%Y-%m-%d"),
"credits": 0, "products": []}
for query in queries:
for platform in platforms:
body = search(platform, query)
out["credits"] += body.get("credits_used", 0)
for item in body["data"]["products"][:5]:
row = normalize(platform, item)
row["query"] = query
row["platform"] = platform
out["products"].append(row)
return out
daily = snapshot(["airpods pro 2", "dyson v15", "roomba j7"])
with open(f"prices_{daily['date']}.json", "w") as f:
json.dump(daily, f, indent=2)
print(f"{len(daily['products'])} rows for {daily['credits']} credits")Accumulating credits_used into the snapshot means your cost per run is recorded next to the data it bought. When the bill moves you can tell whether volume grew or a domain got more expensive, which is the difference between a five-minute answer and an afternoon in the billing dashboard.
API Cost Comparison
Amazon PA-API is free with an Associates account but requires generating sales to maintain access. The Walmart affiliate API is free with approval. Both mean maintaining affiliate standing and separate integrations, and both cut you off from data on products you do not already sell.
Scavio bills credits at $0.01, from $30/month, with a 5,000 credit minimum on one-off top-ups. Amazon and Walmart both cost 1 credit per call, so the pricing question reduces to call volume rather than a per-platform matrix.
When You Need Platform-Specific APIs
If you need inventory levels, BSR rankings, variant details, or full product specifications, you need the platform-specific APIs. Search APIs return what appears in search results: titles, prices, ratings, and URLs. For product comparison, pricing intelligence, and market research, search result data is sufficient. For catalog management, inventory tracking, or listing optimization, you need the official APIs.