Apinoa Docs

Filters

The filter vocabulary shared by every marketplace search — names, units, and which marketplace accepts which.

View raw .mdx

Search narrows the same way everywhere. One name per concept, one unit per concept, and a marketplace either honours a filter or rejects it by name.

Every filter is optional, and filtering costs nothing extra — except brands and facets on Amazon, which cost 2 units (see below).

The Vocabulary

ParameterTypeMeaning
priceMinnumberLowest price to return, in decimal major units (40, 10.5)
priceMaxnumberHighest price to return, same unit
brandsstring listBrand names as the marketplace spells them: brands=Nike,Adidas
ratingMinnumberLowest average star rating, on the marketplace's 0–5 scale
conditionenumnew · used · refurbished
freeShippingbooleanOnly listings the marketplace advertises as shipping free
inStockbooleanOnly listings the marketplace reports as purchasable now
sortenumResult ordering — see below
categoryIdstringThe marketplace's own category id — see below
facetslistNarrowings from the result's own filter rail: facets=Sock Rise:Ankle,Color:Black

priceMin/priceMax are in the same unit the response reports. Money.amount is decimal major units, so priceMin=40 and a returned {"currency":"USD","amount":40} mean the same thing. Marketplaces that want minor units convert internally; you never see cents.

A list is comma-separated over a query string and a real array over a JSON body. Both are the same request:

?brands=Nike,Adidas          {"brands": ["Nike", "Adidas"]}

Booleans accept true/false/1/0. freeShipping=false really means false.

Who Accepts What

AmazonShopifyWalmartAliexpress
priceMin / priceMax✅✅✅✅
categoryId✅✅✅✅
sort✅—✅✅
brands✅ (costs 2)—✅—
ratingMin⚠️ 4 only✅✅—
condition—⚠️ no refurbished——
inStock—✅——
facets✅ (costs 2)—✅—

freeShipping is part of the shared vocabulary, but no marketplace currently served accepts it.

A dash means a 400 naming the parameter, not a quiet no-op.

The gaps are the marketplaces', not ours. Where a filter is missing it is because the marketplace has none: AliExpress's search has no rating refinement, Shopify sells no refurbished tier (so condition=refurbished is refused rather than folded into used — different claims) and offers no sort at all.

Amazon's rating rail has exactly one threshold, "4 Stars & Up" — hence ratingMin=4 and a 400 for anything else, rather than quietly answering a ratingMin=3 request with 4-and-up results.

categoryId

There is no shared category taxonomy, so the id is the marketplace's own: a browse node on Amazon (679416011), a cat_id on Walmart (4171), a category id on AliExpress (200000345), a Standard Product Taxonomy id on Shopify (aa-1-13-8).

Where the ids come from. Ask for them: categories lists a level of the marketplace's own taxonomy, and browse takes what it returns. Call it with no categoryId for the top level and walk down, or start from an id in a Product.category[].

Two cautions the endpoint pages spell out: an id is not always usable on every operation (Walmart's search takes a bare cat_id, its browse needs the underscore chain that categories returns), and a few levels are navigational only, marked "browsable": false.

On search it narrows a keyword query rather than replacing it, and query stays required.

To list a category with no keyword at all, use the browse operation instead, where categoryId is required and query is rejected. Every marketplace except Shopify has it, and it takes the same filters search does. Two things differ from search and are worth knowing before you call it:

  • The id can be a different kind of thing. Walmart's browse wants the underscore-joined chain (3944_133251_1095191_1230614_1230478), not the bare cat_id its search takes.
  • A bad id is not always an error. AliExpress returns an empty items — it does not distinguish an unknown category from an empty one.

Facets — the Marketplace's Own Filter Rail

The typed filters above are the ones every marketplace has in common. They are a small slice of what a site actually offers: one Walmart socks search renders 25 filter groups, of which four map onto a typed parameter. The other twenty-one — Sock Rise, Sleeve Length, Fabric Material, Weather Suitability — are specific to that query. Search a laptop and they are replaced by Screen Size and RAM.

Because the rail is per-query, it is discovered rather than declared. A search response carries it:

{
  "items": [ "…" ],
  "facets": [
    { "id": "sock_rise", "name": "Sock Rise", "kind": "select",
      "values": [ { "value": "Ankle", "name": "Ankle", "count": 412 } ] },
    { "id": "brand", "name": "Brand", "kind": "select", "maps_to": "brands",
      "values": [ { "value": "Hanes", "name": "Hanes" } ] },
    { "id": "price", "name": "Price", "kind": "range", "maps_to": "priceMin", "min": 0, "max": 45 }
  ]
}

Send a value back with facets:

curl "https://gateway.apinoa.com/v1/walmart/search?query=socks&facets=sock_rise:Ankle,color:Black" \
  -H "x-api-key: $APINOA_API_KEY"

maps_to names the typed filter covering the same concept, where there is one. Prefer the typed parameter — it means the same thing on every marketplace, and facets does not.

Who Has a Rail

DiscoverApplyNotes
walmart✅✅free both ways
amazon✅ include=facets✅discovery is 1 unit; applying is 2 — see below
shopify[]—Shopify search has no filter rail
aliexpress——no rail

An absent facets means no rail was returned. An empty one means there is no rail for this query. Shopify reports [].

Amazon: Discovery Is 1 Unit, Applying Is 2

Two different things, and only one of them costs extra.

include=facets costs 1 unit — the same as a search without it.

brands and facets cost 2 units. cost.search is 1..2. Everything else on Amazon still costs 1.

A label the rail does not carry is a 400 naming it, with a sample of what the rail did offer. Amazon truncates its rail, so an unmatched label is genuinely ambiguous — returning unfiltered results would hide that, and returning none would be a guess.

Sort

ValueMeaningAmazonWalmartAliexpress
best_matchthe marketplace's own relevance✅✅—
price_ascprice, low to high✅✅✅
price_descprice, high to low✅✅✅
newly_listedmost recently listed✅✅—
best_sellerby units sold—✅✅
avg_reviewby average rating✅——

The names are ours; each marketplace's own code is internal. A value a marketplace cannot do is a 400.

Examples

# under $40, four stars and up
curl "https://gateway.apinoa.com/v1/amazon/search?query=running+shoes&priceMax=40&ratingMin=4" \
  -H "x-api-key: $APINOA_API_KEY"

# Nike only, rated 4+, cheapest first
curl "https://gateway.apinoa.com/v1/walmart/search?query=running+shoes&brands=Nike&ratingMin=4&sort=price_asc" \
  -H "x-api-key: $APINOA_API_KEY"

# in stock, $20-$60, rated 4+
curl "https://gateway.apinoa.com/v1/shopify/search?query=wool+socks&priceMin=20&priceMax=60&ratingMin=4&inStock=true" \
  -H "x-api-key: $APINOA_API_KEY"

One Caveat Worth Knowing

A price bound filters the listing, and some listings carry a price range rather than a price. A product whose variants run $28–$50 satisfies a priceMin=40 request through its $50 variant, while its card reports the "from" price of $28.

So a few returned rows can sit just outside the band you asked for. Measured, 90–95% land inside it. If you need a hard bound, filter the returned price yourself — the marketplaces behave this way and we report what they return rather than hiding rows.

On this page