Developer API reference
The SmartScout Developer API is a REST API that accepts and returns JSON. It exposes the Amazon marketplace intelligence behind the SmartScout platform: product and brand estimates, seller coverage, subcategory structure, search term data, and ad-spy signals across twelve marketplaces.
https://api.smartscout.comCopyX-Api-Key header and a marketplace query parameter.curl -X POST 'https://api.smartscout.com/api/v1/products/search?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"brandName": "Nordic Naturals"}' Python
import requests
r = requests.post(
"https://api.smartscout.com/api/v1/products/search",
params={"marketplace": "US"},
headers={"X-Api-Key": "YOUR_API_KEY"},
json={"brandName": "Nordic Naturals"},
)
print(r.json()["data"])
Node
const res = await fetch(
"https://api.smartscout.com/api/v1/products/search?marketplace=US",
{
method: "POST",
headers: {
"X-Api-Key": process.env.SMARTSCOUT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ brandName: "Nordic Naturals" }),
}
);
const body = await res.json();Getting started
Authentication
Every request requires an API key in the X-Api-Key header. Keys are issued by the SmartScout team; there is no self-serve signup. To rotate a key, reach out to your account manager.
Your first request
This call needs no IDs and returns immediately. An empty filter body returns the first page of results.
curl -X POST 'https://api.smartscout.com/api/v1/subcategories/search?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{}'
Python:
import requests
r = requests.post(
"https://api.smartscout.com/api/v1/subcategories/search",
params={"marketplace": "US"},
headers={"X-Api-Key": "YOUR_API_KEY"},
json={},
)
print(r.json()["data"])
Node:
const res = await fetch(
"https://api.smartscout.com/api/v1/subcategories/search?marketplace=US",
{
method: "POST",
headers: {
"X-Api-Key": process.env.SMARTSCOUT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
}
);
const body = await res.json();Core conventions
Learn these five rules and the whole API becomes predictable.
1 · The marketplace parameter is always required
Every endpoint takes a marketplace query string parameter. Omit it and the request fails.
| Region | Values |
|---|---|
| North America | US, CA, MX |
| Europe | UK, DE, FR, IT, ES |
| Asia Pacific | IN, AU, JP |
| Middle East | AE |
2 · Search endpoints are POST, reads are GET
Anything that filters a collection is a POST with a JSON filter body. Anything that fetches a known record or its history is a GET with path and query parameters.
3 · Every list response uses the same envelope
{
"data": [ ... ],
"paging": {
"nextPageId": "string",
"hasMoreRecords": true
}
}4 · Pagination is cursor-based
Read paging.hasMoreRecords. If it is true, pass paging.nextPageId as the page[id] query parameter on your next request. Set page[size] to request fewer records. Each endpoint has a built-in ceiling, and a page[size] above that ceiling gets ignored rather than raising an error.
GET /api/v1/sellers/ABC123/offers?marketplace=US&page[id]=eyJsYXN0SWQiOjEwMH0import requests
def fetch_all(path, marketplace, filters, api_key):
results, page_id = [], None
while True:
params = {"marketplace": marketplace}
if page_id:
params["page[id]"] = page_id
r = requests.post(
f"https://api.smartscout.com{path}",
params=params,
headers={"X-Api-Key": api_key},
json=filters,
)
r.raise_for_status()
body = r.json()
results.extend(body["data"])
if not body["paging"]["hasMoreRecords"]:
return results
page_id = body["paging"]["nextPageId"]async function fetchAll(path, marketplace, filters, apiKey) {
const results = [];
let cursor = null;
while (true) {
const params = new URLSearchParams({ marketplace });
if (cursor) params.set("page[id]", cursor);
const res = await fetch(
"https://api.smartscout.com" + path + "?" + params,
{
method: "POST",
headers: {
"X-Api-Key": apiKey,
"Content-Type": "application/json",
},
body: JSON.stringify(filters),
}
);
if (!res.ok) throw new Error("Request failed: " + res.status);
const body = await res.json();
results.push(...body.data);
if (!body.paging.hasMoreRecords) return results;
cursor = body.paging.nextPageId;
}
}# First page
curl -X POST 'https://api.smartscout.com/api/v1/products/search?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{}'
# Next page: pass paging.nextPageId from the previous response as page[id]
curl -X POST 'https://api.smartscout.com/api/v1/products/search?marketplace=US&page[id]=eyJsYXN0SWQiOjEwMH0' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{}'
# Repeat while paging.hasMoreRecords is true5 · Sorting works on any returned field
Pass sort[by] with a field name from the response object, and sort[order] as asc or desc.
?marketplace=US&sort[by]=monthlyRevenueEstimate&sort[order]=descFilter grammar
Filter bodies are flat JSON objects keyed by field name. Two forms exist: a shorthand for exact matches, and an object form for everything else.
{ "amazonSellerId": "ATVPDKIKX0DER" }{
"amazonSellerId": {
"type": "startsWith",
"filter": "ATVPD"
}
}Text matching rules
| Rule | Matches |
|---|---|
| equals | Exact value |
| notEquals | Anything except the value |
| startsWith | Value at the beginning |
| endsWith | Value at the end |
| contains | Value anywhere |
| notContains | Absence of the value |
| blanks | Empty or null fields |
Numeric ranges
Number fields take min, max, or both. An exact number also works.
{ "monthlyRevenueEstimate": { "min": 10, "max": 1000 } }{ "monthlyRevenueEstimate": { "min": 10 } }{ "monthlyRevenueEstimate": 1000 }Combining filters
Keys in the same object combine with AND. This finds US products in a sales band whose brand name starts with "Nordic".
{
"brandName": { "type": "startsWith", "filter": "Nordic" },
"monthlyRevenueEstimate": { "min": 5000, "max": 50000 }
}Build a filter body
Example configuration — field, rule, and value below map directly to the JSON shown.
{ "brandName": { "type": "startsWith", "filter": "Nordic" } }Versioning
Two earlier generations of the Brands surface have been retired and no longer respond: the v1 Brands endpoints, which carried brand names in the URL path, and the four v2 Brands history endpoints that preceded history/scope. Everything listed in the catalog is live.
/api/v2/brands/history/sales
/api/v2/brands/history/sales-by-subcategories
/api/v2/brands/history/top-products/sales
/api/v2/brands/history/top-products/sales-rank
history/scope is the current pattern across Brands, Products, and Subcategories: one call for revenue, units, price, and ASIN count. Brand and Subcategory scope share a shape; Product scope does not, so parse it separately.Endpoint catalog
36 endpoints across 9 groups, reconciled against the live API on August 20, 2026.
Product estimates, offers, and history for a single ASIN.
| Method | Path | Sends / returns | Description |
|---|---|---|---|
| POST | # /api/v1/products/search | SearchProductsRequest Product | Search and filter the product database |
| GET | # /api/v1/products/{Asin}/history | — ProductHistory | Buy box price and sales rank history for one ASIN |
| POST | # /api/v1/products/{Asin}/history/scope | GetProductHistoryScopeRequest ScopeHistory | Scoped history for one ASIN. Note: a different response shape from Brand and Subcategory scope |
| GET | # /api/v1/products/{Asin}/offers | — ProductOffer | Current offers on an ASIN across all sellers |
| GET | # /api/v1/products/{Asin}/history/offersWhite-label license required | — GetOfferHistoryResponse | Historical offer composition for an ASIN |
The current Brands surface. The history/scope family returns revenue, units, price, and ASIN count in one call.
| Method | Path | Sends / returns | Description |
|---|---|---|---|
| POST | # /api/v2/brands/search | SearchBrandsV2Request Brand | Search and filter brands |
| GET | # /api/v2/brands/market-share | — SubcategoryBrand | A brand's market share broken out by subcategory |
| GET | # /api/v2/brands/sellers | — BrandCoverage | Sellers carrying a brand |
| GET | # /api/v2/brands/ad-spy | — BrandSearchTerm | Ad-spy data for the search terms a brand competes on |
| POST | # /api/v2/brands/history/scope | GetBrandScopeRequest BrandScope | Brand history: revenue, units, price, ASIN count |
| POST | # /api/v2/brands/history/scope/by-subcategories | GetBrandScopeBySubcategoriesRequest BrandScopeBySubcategory | Brand history split by subcategory |
| POST | # /api/v2/brands/history/scope/top-products | GetBrandScopeTopProductsRequest TopProductScope | Scoped history for a brand's top products |
| POST | # /api/v2/brands/history/scope/by-sellers | GetBrandCoverageByBrandHistoryRequest BrandCoverageBySellerHistory | Brand history split by seller |
Seller search, current offers, brand coverage, and feedback history.
| Method | Path | Sends / returns | Description |
|---|---|---|---|
| POST | # /api/v1/sellers/search | SearchSellersRequest Seller | Search and filter sellers |
| GET | # /api/v1/sellers/{AmazonSellerId}/offers | — SellerOffer | A seller's current offers |
| GET | # /api/v1/sellers/{AmazonSellerId}/brands | — BrandCoverage | Brands a seller carries |
| POST | # /api/v1/sellers/{AmazonSellerId}/history/scope/by-brands | GetBrandCoverageBySellerHistoryRequest BrandCoverageByBrandHistory | A seller's brand coverage over time |
| GET | # /api/v1/sellers/{AmazonSellerId}/history | — SellerHistory | Seller feedback and review history |
Subcategory structure, the brands competing inside one, and scoped history.
| Method | Path | Sends / returns | Description |
|---|---|---|---|
| POST | # /api/v1/subcategories/search | SearchSubcategoriesRequest Subcategory | Search and filter subcategories |
| POST | # /api/v1/subcategories/{SubcategoryId}/brands | GetSubcategoryBrandsRequest SubcategoryBrand | Brands competing in a subcategory |
| POST | # /api/v1/subcategories/{SubcategoryId}/history/scope | — SubcategoryScope | Scoped history for a subcategory: revenue, units, price, ASIN count |
| POST | # /api/v1/subcategories/{SubcategoryId}/history/scope/by-brands | — SubcategoryScopeByBrand | Subcategory history split by brand |
| POST | # /api/v1/subcategories/{SubcategoryId}/history/scope/top-products | — TopProductScope | Scoped history for a subcategory's top products |
| GET | # /api/v1/subcategories/{SubcategoryId}/hierarchy | — Subcategory | The category tree path for a subcategory |
Search volume, organic rank, and the keyword neighborhood around an ASIN.
| Method | Path | Sends / returns | Description |
|---|---|---|---|
| POST | # /api/v1/search-terms/search | SearchSearchTermsRequest SearchTerm | Search and filter search terms, including volume |
| POST | # /api/v1/search-terms/history | GetSearchTermHistoryRequest SearchTermHistory | Search volume history for a term |
| POST | # /api/v1/search-terms/organic-ranks | GetOrganicRanksRequest SearchTermProductRank | Organic ranking positions for products on a term |
| POST | # /api/v1/search-terms/relevant-products/{Asin} | GetRelevantProductsRequest RelevantProduct | Competing products sharing keyword overlap with an ASIN |
| POST | # /api/v1/search-terms/relevant-search-terms/{Asin} | GetRelevantSearchTermsRequest RelevantSearchTerm | Terms driving traffic to an ASIN |
Sponsored placements and the brands advertising on a term.
| Method | Path | Sends / returns | Description |
|---|---|---|---|
| GET | # /api/v1/ad-spy/sponsored-products | — SearchTermProduct | Sponsored product placements, filterable by term or brand |
| GET | # /api/v1/ad-spy/{SearchTermValue}/brands | — SearchTermBrand | Brands advertising on a search term |
| POST | # /api/v1/ad-spy/search | SearchSearchTermsRequest SearchTerm | Search and filter ad-spy search terms |
Segments are built in the SmartScout app and read programmatically here.
| Method | Path | Sends / returns | Description |
|---|---|---|---|
| POST | # /api/v1/custom-segments/search | SearchCustomSegmentsRequest CustomSegment | Query a segment built in the SmartScout app by its Public API Id |
The rank-to-sales estimation model, exposed directly. The output is an estimate.
| Method | Path | Sends / returns | Description |
|---|---|---|---|
| GET | # /api/v1/sales/estimate | categoryNode, salesRank SalesEstimate | Estimated sales for a rank within a category node |
The data behind the buy box map. Asynchronous: submit a request, receive an ID, then poll for the result.
Recipes
Organized by the job, not the endpoint. Most readers arrive with a question rather than an endpoint in mind.
Read a custom segment from the API
#Segments are built in the SmartScout app, where an analyst can iterate on the definition visually. POST /api/v1/custom-segments/search takes a filter, so once a segment exists you can query it from the API by its Public API Id. That closes the loop between the app and the API: define the set once, read it on a schedule.
- Open My custom segments in the SmartScout app
- Open the Columns panel on the right edge of the table
- Check Public API Id
- The column appears in the table. Copy the value for the segment you want — a short alphanumeric string, for example
s9jgl6s - Pass it as a filter to
POST /api/v1/custom-segments/search
Track a brand's revenue trend
#POST /api/v2/brands/history/scope returns revenue, units, price, and ASIN count per period in a single call.
curl -X POST 'https://api.smartscout.com/api/v2/brands/history/scope?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"brandName": "Nordic Naturals"}'import requests
r = requests.post(
"https://api.smartscout.com/api/v2/brands/history/scope",
params={"marketplace": "US"},
headers={"X-Api-Key": API_KEY},
json={"brandName": "Nordic Naturals"},
)
scope = r.json()["data"]const res = await fetch(
"https://api.smartscout.com/api/v2/brands/history/scope?marketplace=US",
{
method: "POST",
headers: {
"X-Api-Key": apiKey,
"Content-Type": "application/json",
},
body: JSON.stringify({ brandName: "Nordic Naturals" }),
}
);
const scope = (await res.json()).data;Find every seller on a brand
#GET /api/v2/brands/sellers returns current coverage. For how that coverage moved, POST /api/v2/brands/history/scope/by-sellers.
curl 'https://api.smartscout.com/api/v2/brands/sellers?marketplace=US&brandName=Nordic%20Naturals' \ -H 'X-Api-Key: YOUR_API_KEY'
import requests
r = requests.get(
"https://api.smartscout.com/api/v2/brands/sellers",
params={"marketplace": "US", "brandName": "Nordic Naturals"},
headers={"X-Api-Key": API_KEY},
)
sellers = r.json()["data"]const params = new URLSearchParams({
marketplace: "US",
brandName: "Nordic Naturals",
});
const res = await fetch(
"https://api.smartscout.com/api/v2/brands/sellers?" + params,
{ headers: { "X-Api-Key": apiKey } }
);
const sellers = (await res.json()).data;Build a competitive set for an ASIN
#Start with the terms driving traffic to the ASIN, then pull the products sharing that keyword footprint.
curl -X POST 'https://api.smartscout.com/api/v1/search-terms/relevant-search-terms/B00CAXKZ0S?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{}'
curl -X POST 'https://api.smartscout.com/api/v1/search-terms/relevant-products/B00CAXKZ0S?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{}'import requests
ASIN = "B00CAXKZ0S"
base = "https://api.smartscout.com/api/v1/search-terms"
headers = {"X-Api-Key": API_KEY}
params = {"marketplace": "US"}
terms = requests.post(
f"{base}/relevant-search-terms/{ASIN}",
params=params, headers=headers, json={},
).json()["data"]
products = requests.post(
f"{base}/relevant-products/{ASIN}",
params=params, headers=headers, json={},
).json()["data"]const asin = "B00CAXKZ0S";
const base = "https://api.smartscout.com/api/v1/search-terms";
const opts = {
method: "POST",
headers: {
"X-Api-Key": apiKey,
"Content-Type": "application/json",
},
body: "{}",
};
const terms = await (
await fetch(base + "/relevant-search-terms/" + asin + "?marketplace=US", opts)
).json();
const products = await (
await fetch(base + "/relevant-products/" + asin + "?marketplace=US", opts)
).json();Size a category
#Locate the subcategory, then read the brands inside it.
curl -X POST 'https://api.smartscout.com/api/v1/subcategories/search?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{}'
curl -X POST 'https://api.smartscout.com/api/v1/subcategories/281407/brands?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{}'import requests
headers = {"X-Api-Key": API_KEY}
params = {"marketplace": "US"}
subcats = requests.post(
"https://api.smartscout.com/api/v1/subcategories/search",
params=params, headers=headers, json={},
).json()["data"]
subcategory_id = subcats[0]["id"]
brands = requests.post(
f"https://api.smartscout.com/api/v1/subcategories/{subcategory_id}/brands",
params=params, headers=headers, json={},
).json()["data"]const opts = {
method: "POST",
headers: {
"X-Api-Key": apiKey,
"Content-Type": "application/json",
},
body: "{}",
};
const root = "https://api.smartscout.com/api/v1/subcategories";
const subcats = await (
await fetch(root + "/search?marketplace=US", opts)
).json();
const id = subcats.data[0].id;
const brands = await (
await fetch(root + "/" + id + "/brands?marketplace=US", opts)
).json();Monitor buy box competition
#Current offers give the picture now; the offer history shows how it moved.
curl 'https://api.smartscout.com/api/v1/products/B00CAXKZ0S/offers?marketplace=US' \ -H 'X-Api-Key: YOUR_API_KEY' curl 'https://api.smartscout.com/api/v1/products/B00CAXKZ0S/history/offers?marketplace=US' \ -H 'X-Api-Key: YOUR_API_KEY'
import requests
ASIN = "B00CAXKZ0S"
base = f"https://api.smartscout.com/api/v1/products/{ASIN}"
headers = {"X-Api-Key": API_KEY}
params = {"marketplace": "US"}
current = requests.get(f"{base}/offers", params=params, headers=headers).json()
history = requests.get(f"{base}/history/offers", params=params, headers=headers).json()const asin = "B00CAXKZ0S";
const base = "https://api.smartscout.com/api/v1/products/" + asin;
const opts = { headers: { "X-Api-Key": apiKey } };
const current = await (
await fetch(base + "/offers?marketplace=US", opts)
).json();
const history = await (
await fetch(base + "/history/offers?marketplace=US", opts)
).json();See who is advertising on a keyword
#One GET returns the brands competing on a search term.
curl 'https://api.smartscout.com/api/v1/ad-spy/fish%20oil/brands?marketplace=US' \ -H 'X-Api-Key: YOUR_API_KEY'
import requests
r = requests.get(
"https://api.smartscout.com/api/v1/ad-spy/fish oil/brands",
params={"marketplace": "US"},
headers={"X-Api-Key": API_KEY},
)
brands = r.json()["data"]const term = encodeURIComponent("fish oil");
const res = await fetch(
"https://api.smartscout.com/api/v1/ad-spy/" + term + "/brands?marketplace=US",
{ headers: { "X-Api-Key": apiKey } }
);
const brands = (await res.json()).data;Audit a seller
#Find the seller, then read what they carry, what they are listing now, and how their feedback has trended.
curl -X POST 'https://api.smartscout.com/api/v1/sellers/search?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"amazonSellerId": {"type": "startsWith", "filter": "ATVPD"}}'
curl 'https://api.smartscout.com/api/v1/sellers/ATVPDKIKX0DER/brands?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY'
curl 'https://api.smartscout.com/api/v1/sellers/ATVPDKIKX0DER/history?marketplace=US' \
-H 'X-Api-Key: YOUR_API_KEY'import requests
headers = {"X-Api-Key": API_KEY}
params = {"marketplace": "US"}
root = "https://api.smartscout.com/api/v1/sellers"
matches = requests.post(
f"{root}/search", params=params, headers=headers,
json={"amazonSellerId": {"type": "startsWith", "filter": "ATVPD"}},
).json()["data"]
seller_id = matches[0]["amazonSellerId"]
brands = requests.get(f"{root}/{seller_id}/brands", params=params, headers=headers).json()
offers = requests.get(f"{root}/{seller_id}/offers", params=params, headers=headers).json()
history = requests.get(f"{root}/{seller_id}/history", params=params, headers=headers).json()const root = "https://api.smartscout.com/api/v1/sellers";
const auth = { "X-Api-Key": apiKey };
const matches = await (
await fetch(root + "/search?marketplace=US", {
method: "POST",
headers: {
"X-Api-Key": apiKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
amazonSellerId: { type: "startsWith", filter: "ATVPD" },
}),
})
).json();
const id = matches.data[0].amazonSellerId;
const brands = await (
await fetch(root + "/" + id + "/brands?marketplace=US", { headers: auth })
).json();
const history = await (
await fetch(root + "/" + id + "/history?marketplace=US", { headers: auth })
).json();Errors
Five status codes cover everything the API returns.
| Code | Meaning | What to do |
|---|---|---|
| 400 | Bad request — a required body is missing, or a business validation failed | Fix the request. Do not retry unchanged. |
| 401 | Unauthorized — missing or invalid API key | Check the X-Api-Key header. If the key should be valid, ask your account manager. |
| 403 | Forbidden — authenticated, but not allowed to access this resource | The key is good; the account lacks access. Talk to your account manager. |
| 429 | Too many requests — rate limited | Wait the number of seconds in the Retry-After header, then retry. |
| 500 | Internal server error — everything else | Retry with exponential backoff. If it persists, contact support. |
Retry-After header giving the seconds to wait. Honor it instead of guessing at a backoff schedule.Field reference
Generated from swagger.json at page build time rather than maintained by hand. The spec groups schemas into three families, and this section keeps that structure.
Product, Brand, Seller, Subcategory, SearchTerm, BrandScope, BrandCoverage, ProductOffer, and the history variants.Coverage boundaries
What the API does not cover today. A client who learns the boundary here does not spend a week looking for something that is not there.