Product Query
The unified product query API — single-product lookups, filtered lists, pagination, and bulk extraction with explicit pricing context and configurable response shape.
Overview
The Product Query API is the primary way to fetch products in Omnium. Two endpoints cover every fetch pattern:
POST /api/products/Query— single-product lookups, filtered lists, paginated UI queriesPOST /api/products/Query/Scroll— bulk extraction (catalog syncs, exports, reindexing, delta replication)
Both endpoints return full OmniumProduct models and accept the same filter set. They differ only in pagination model: offset-based (Query) vs. streaming (Query/Scroll).
These endpoints replace POST /api/products/Search, POST /api/products/Scroll, and the various ByMarket/ByStore/ByCustomer GET endpoints. The legacy endpoints still work but are scheduled for deprecation.
Picking an endpoint
| You're doing… | Use |
|---|---|
| Fetching one product (with optional pricing context) | POST /Query |
| Showing a paginated list in a UI | POST /Query |
| Filtering products with text search, tags, categories | POST /Query |
| Replicating products to another system (PIM, ERP, marketplace) | POST /Query/Scroll |
| Exporting or reindexing the full catalog | POST /Query/Scroll |
Anything past offset Take * Page = 10,000 | POST /Query/Scroll |
ID lookups
Four ID-shaped fields cover every lookup pattern. Choose the one that matches what you actually have:
| Field | Matches | Use when |
|---|---|---|
productIds | Product.ProductId only | You have business product IDs |
skuIds | Product.SkuId OR Variants[].SkuId | You have SKU codes (SKU treated as one logical concept regardless of product- or variant-level) |
ids | Product.Id (internal Omnium document id) | You have internal IDs |
anyIds | Any of the above plus ParentId | You don't know what kind of ID you have (barcode scanning, dirty data imports, customer-supplied IDs) |
The strict fields (productIds, skuIds, ids) are precise and predictable. anyIds is the fuzzy option — it matches across all ID-shaped fields, useful when consumers don't know the ID source upfront.
Pricing context
marketIds, storeIds, customerId, customerGroups, storeGroupIds, additionalPriceStoreIds, priceValidFrom, and priceValidTo filter:
- Which products are returned — availability, market eligibility, store assortment
- Which prices on those products come back — only prices matching the context
Set includeAllPrices: true to keep the product filtering but disable the price filter — useful for price-management UIs that need every price for the products in a market.
Field selection — shape your response
Use fields.exclude* flags to drop heavy parts of the response, or fields.include to opt into a narrow set:
Exclude flags (booleans):
excludeAssets,excludeInventory,excludePropertiesexcludeVariants,excludePrices,excludeCategories
Include list (strings):
- Top-level fields:
["productId", "name", "prices"] - Nested variant subfields:
["variants.skuId", "variants.size"]
When fields.include lists nested variant subfields, every other variant field is stripped from the response. Useful for cart pickers and barcode-scanner UIs.
Response size guidance
The default response includes the full product model — variants, prices, assets, inventory, properties. Approximate per-product wire size:
| Configuration | Size per product |
|---|---|
| Default (full model) | ~20–50 KB |
fields.excludeAssets | ~10–30 KB |
excludeAssets + excludeInventory + excludeProperties | ~3–8 KB |
fields.include: ["productId","name","prices"] | ~1 KB |
For high-volume queries (take ≥ 100, scroll batches), exclude fields aggressively. A 500-product scroll batch can exceed 10MB at default settings; the excludeAssets + excludeInventory + excludeProperties pattern trims that to roughly 2MB.
Recipes
Single product with market pricing
The simplest case: one product with prices filtered to one market.
Single product with B2B / customer-group pricing
Returns the product with the customer's prices applied. Customer-specific prices take precedence over group prices, which take precedence over general prices.
Product browse / search list (lightweight)
Typical for product browse and search UI. Heavy fields excluded to keep batches tight and fast.
Cart picker — minimal variant fields per product
Variants in the response will contain only skuId and size; every other variant field is stripped. Use this for cart pickers, barcode-scanner reverse lookups, and any UI needing minimal variant metadata.
Multi-property filter (AND)
Returns products matching ALL listed property pairs.
Bulk export — full catalog scroll, lightweight
Streams every active product through scroll batches.
Delta sync — replicate changes to another system
The canonical "replicate to another system" pattern. With isUnionDeltaQuery: true the date windows OR together, so one request captures every product touched in the window: modifications, publish/unpublish events, and price activations/deactivations.
Run this on a 5-minute cron for an idempotent product sync pipeline. Persist the From timestamp from your last successful run and use it as the next From. See Delta Queries for the full predictive-window pattern.
Pagination vs scroll mechanics
POST /Query (offset pagination)
take— page size. Default 10. Max 1000.page— 1-indexed page number. Default 1.- Hard cap:
take * page < 10,000. Past that, switch to scroll.
POST /Query/Scroll (streaming)
scrollSize— batch size. Default 500. Allowed range: 100–1000.- Returns
scrollIdplus the first batch. - Continue with
GET /api/products/Query/Scroll/{scrollId}untilscrollIdis null. - Sessions expire after 10 minutes of inactivity.
- Per-tenant cap on concurrent active scrolls.
- Scroll skips post-processing (inventory zero-stripping, property-list filtering) for batch consistency across batches.
Always finish a scroll. Unfinished scrolls hold a snapshot context on the server until the inactivity timeout expires, consuming resources unnecessarily. Per-tenant concurrency is also capped, so leaking scrolls will cause new ones to be rejected.
Rate limiting
Both endpoints use a generous concurrency policy. The scroll endpoints additionally enforce a strict per-tenant concurrency limit (default 3 active scrolls) to protect the search cluster. If a fourth concurrent scroll is attempted, the request is rejected with HTTP 429.
Swagger reference
For the full interactive API reference and request/response schemas, see the swagger documentation.
