Skip to main content
GET
Search for a product and where to buy it nearby

Query Parameters

q
string
required

Search query text.

Required string length: 1 - 255
Pattern: ^[^\x00]{1,255}$
latitude
number

Latitude in decimal degrees (WGS84). Pair with longitude.

Required range: -90 <= x <= 90
longitude
number

Longitude in decimal degrees (WGS84). Pair with latitude.

Required range: -180 <= x <= 180
postal_code
string

Postal code to resolve to a location when latitude/longitude aren't available. Ignored when latitude/longitude are both given. Resolved against Closient's own store location data (no third-party geocoder); returns 422 if it cannot be resolved.

Pattern: ^[^\x00]{0,}$
radius_km
number
default:25

Search radius in kilometers from the resolved location.

Required range: x <= 100
retailer_id
string

Scope to one retailer's stores (a retailer/store landing page's own search box). Distinct from retailer, the multi-select facet filter — both apply together if both are set.

Pattern: ^[^\x00]{0,}$
store_id
string

Scope to one physical store. Skips distance sorting — answers whether this store has it.

Pattern: ^[^\x00]{0,}$
include_online
boolean
default:false

Include online offers even when local results are non-empty.

page
integer
default:1

Page number of local results.

Required range: 1 <= x <= 10000000
page_size
integer
default:20

Local results per page.

Required range: 1 <= x <= 100
retailer
string[]

C-4718 facet: filter offers to one or more retailer ids. Repeat the parameter for multiple.

Pattern: ^[^\x00]{0,}$
brand
string[]

Filter BM25 candidates to one or more brand names (case-insensitive). Repeat for multiple.

Pattern: ^[^\x00]{0,}$
category
string[]

Filter BM25 candidates to one or more category paths (case-insensitive). Repeat for multiple.

Pattern: ^[^\x00]{0,}$
availability_confidence
enum<string>[]

Filter offers to one or more confidence levels. Repeat the parameter for multiple.

Mirror of apps.retailers.models.InventoryConfidence (C-4099/C-4716).

Computed at OpenSearch index time from an offer's stock signals (source provenance, freshness, quantity) rather than stored on the offer row itself — see apps.retailers.services.inventory.calculate_confidence. Surfaced on every availability index document as availability_confidence and echoed on each local/online offer row returned by the product search endpoint.

Available options:
confirmed,
likely,
uncertain,
unknown,
out_of_stock
price_min
number

Minimum offer price.

Required range: x >= 0
price_max
number

Maximum offer price.

Required range: x >= 0
accuracy_m
number

Reported accuracy in meters of latitude/longitude, when the caller has one (e.g. the browser Geolocation API's own accuracy reading). Never affects search results — captured only for the C-4723 demand-signal event, where it gates whether at_store_candidate is computed.

Required range: x >= 0
source_surface
enum<string>
default:api

Which UI surface issued this request. Never affects search results — captured only for the C-4723 demand-signal event.

Available options:
navbar,
scan_page,
watching_notice,
esl,
mcp,
api

Response

OK

Response envelope for GET /search/products.

query
string
required

The search query that was executed.

is_automatic_winner
boolean
required

True when the top BM25 score beat the next distinct product by at least the tunable ratio (1.5x) and the winner can be presented without disambiguation.

local_total_count
integer
required

Total matching physical offers, before pagination.

Required range: x >= 0
page
integer
required

Page number of local results returned.

Required range: x >= 1
page_size
integer
required

Page size applied to local results.

Required range: x >= 1
winner
ProductSummaryOut · object | null

The best-matching product. Null only when the query matched nothing at all.

Example:
disambiguation
ProductSummaryOut · object[]

Other distinct near-scoring products, for C-4718 disambiguation chips. Always empty when is_automatic_winner is true.

local
LocalOfferOut · object[]

The winner's physical stores, sorted by distance (or unsorted if no location was given).

online
OnlineOfferOut · object[]

The winner's online offers. Populated only when local is empty or include_online is set.

online_shown_because
enum<string> | null

Why the online section is populated. Null when online is empty.

Available options:
no_local_results,
requested
facets
FacetsOut · object

Facet aggregations over the candidate pool.

Example:
search_request_id
string | null

Correlation token for this search (C-4721) — pass it to POST /search/api/v1/search/click when the caller reports a post-search interaction (a result was clicked, the radius was expanded, etc.), so the click can be attributed back to this search for CTR-by-position measurement. Null only if demand-signal capture itself failed to dispatch (never surfaces as a request error — see apps.search.services.demand_signal.dispatch_capture); a caller that gets null has nothing meaningful to click-report against.