---
title: "Filters"
description: "The filter vocabulary shared by every marketplace search — names, units, and which marketplace accepts which."
---

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

| Parameter | Type | Meaning |
|---|---|---|
| `priceMin` | number | Lowest price to return, in **decimal major units** (`40`, `10.5`) |
| `priceMax` | number | Highest price to return, same unit |
| `brands` | string list | Brand names as the marketplace spells them: `brands=Nike,Adidas` |
| `ratingMin` | number | Lowest average star rating, on the marketplace's 0–5 scale |
| `condition` | enum | `new` · `used` · `refurbished` |
| `freeShipping` | boolean | Only listings the marketplace advertises as shipping free |
| `inStock` | boolean | Only listings the marketplace reports as purchasable now |
| `sort` | enum | Result ordering — see below |
| `categoryId` | string | The marketplace's own category id — see below |
| `facets` | list | Narrowings 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

| | Amazon | Shopify | Walmart | Aliexpress |
|---|:---:|:---:|:---:|:---:|
| `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:

```json
{
  "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`:

```bash
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

| | Discover | Apply | Notes |
|---|:---:|:---:|---|
| **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

| Value | Meaning | Amazon | Walmart | Aliexpress |
|---|---|:---:|:---:|:---:|
| `best_match` | the marketplace's own relevance | ✅ | ✅ | — |
| `price_asc` | price, low to high | ✅ | ✅ | ✅ |
| `price_desc` | price, high to low | ✅ | ✅ | ✅ |
| `newly_listed` | most recently listed | ✅ | ✅ | — |
| `best_seller` | by units sold | — | ✅ | ✅ |
| `avg_review` | by average rating | ✅ | — | — |

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

## Examples

```bash
# 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.
