Skip to main content
Scope catalogue:read. This is not a second search: the same parser reads the words and the same index ranks what is left, because a phone showing other results than the website for the same words is a bug nobody can explain.
You do not need words. A request that only narrows — filter[brand][]=Rolex — is answered by the index too, with the same counts. Browsing by brand is the same question as searching for one, and a filter panel is used far more often than a search box.

Drawing the panel before anybody has touched it

An empty filter[q] is a search with no words: the whole catalogue, ranked, with every facet and its counts. That is the call to make when the screen opens, before somebody has typed or picked anything. Leaving the parameter off altogether is a different request — the plain cursor-paged list, which carries no facets because nothing was searched. filter[seller] narrows any of this to one business — the shop page’s question. It takes an id rather than a name, because two businesses share a name, and it combines with words and facets like anything else: “everything this shop has under €5,000” is one request. That is the published catalogue. A seller’s own stock, drafts and sold listings included, is /v1/sellers/{id}/watches and needs watches:read for that business. A price range needs only the end you have: filter[price][min]=500000 on its own means “from €5,000”, and filter[price][max] on its own means “up to”. Amounts are cents, like every other amount here.

What the parser does with the words

Before anything is searched, the words are read for things that are not words: Whatever is left over is what the index actually searches on. It reads Dutch, English, German, French, Spanish, Italian, Portuguese, Finnish and Polish, because sellers and buyers type in all of them.

What comes back

integer
A count, not an estimate. The index is asked for a numbered page, which makes it count the whole matching set rather than stopping as soon as it can answer.
integer
How many pages that is, at the size you asked for.
object
The filter panel, keyed by the name you send back to filter on. A facet has a name and a group to head it with, and either options — each a value, a label, a count and whether it is active — or a range, for price.On the first page only. They describe the whole result set rather than the slice, so they are the same on every page and repeating them was most of what made one heavy. Keep the ones you were given.The hundred biggest, plus anything already active — except brand and seller.name, which come whole so an A–Z list of them misses nothing. The index knows every distinct value in the result set, which for watchModel is over a thousand and for reference is roughly one per watch — a list nobody scrolls and a response nobody wants. reference offers none for that reason, and so is left out entirely rather than sent as a heading with nothing under it — filter[reference] still works, because somebody looking for one types it. Any facet that ends up with no options and no range is absent for the same reason, so draw what you are given rather than expecting a fixed set.In the language you asked for. name, group and every option label follow Accept-Language; value never does, because that is what you send back.
object
Where in the list you are, in the same shape every other collection here uses — so a client reads one thing whether somebody typed anything or not. meta.total and meta.pages beside it are the index’s own counts.
boolean
Only present, and only true, when the count stopped at the index’s own ceiling (100,000). A search somebody actually runs never sees it; “everything we have” might.

A facet

Counts describe the narrowed set, so the panel stays honest as somebody ticks things. A facet that nothing in the results has is left out rather than listed with a zero.

Every facet you can filter on

Send them back exactly as they are keyed. All of them are arrays — several values of the same facet widen, different facets narrow.
The values, before you have searched anything: /v1/specifications lists every specification with every value it accepts, and tells you what each one is called as a filter. That is how to draw a full panel on a screen nobody has searched on yet — the facets then fill in the counts.
Facet filters only work on the catalogue. On a seller’s own inventory they are refused with 400, because there is no index behind it: a filter that quietly does nothing looks exactly like one that worked.

Sorting

The words themselves can sort: “goedkoopste rolex” is a price sort with a brand filter, and a sort you send wins over one the words implied. year is the one sort that only works in a search — it is a specification rather than a column, so anywhere else it is refused with 400 search_only_sort rather than ordering “1998” against “2010” as text: on an inventory, and on a plain /v1/watches with neither filter[q] nor a facet (send filter[q]= to sort the whole catalogue by year).

Paging

Numbered, up to 50 per page, because relevance order has no stable cursor and an app wants page two. links.next is there until there is no next; meta.pages says how many there are.
A seller’s own inventory pages by cursor instead — page[after], page[limit] — because walking a live inventory with an offset skips or repeats rows when something is inserted halfway through.

When there is nothing to show

An empty data with meta.total: 0 means nothing matched. If the index is unreachable the answer is 503 with code: search_unavailable — never an empty page, because empty is an answer and it is not this one.