General Query API information
Norce Commerce Query API uses OData v4 over REST. This enables queryable requests towards our database. This API is not cached but a window directly into our database, which makes it necessary to understand our database model. Authorization is through OAuth in the same way as other APIs. You may read more about the OData standard here. Note that we only support read — you cannot manipulate data via this API.
Exploring the model
All endpoints can be explored with a $metadata request to discover entities and data sets:
https://norce-open-demo.api-se.playground.norce.tech/commerce/Query/2.0/Products/$metadataLimits
Paging
List endpoints return a maximum of 500 records per page. When more records exist, the response includes an @odata.nextLink pointing to the next page:
{
"@odata.context": "https://norce-open-demo.api-se.playground.norce.tech/commerce/Query/2.0/Products/$metadata#Products",
"value": [ ... ],
"@odata.nextLink": "https://norce-open-demo.api-se.playground.norce.tech/commerce/Query/2.0/Products/Products?$skip=500"
}Follow @odata.nextLink repeatedly until it is absent. Most OData SDKs handle this automatically.
Expansion depth
You can expand related entities using $expand, but expansion is limited to 3 levels deep. Queries that exceed this will return an error. If you need deeply nested data, split it into separate requests.
Rate limit
This API is rate limited to protect database performance. Exceeding the limit returns HTTP 429 Too Many Requests.
If you hit the limit in an integration context, introduce a delay between requests or restructure queries to fetch more data per request using $expand and $select.
Common OData patterns
Fetch a single entity by key
/ProductSkus('100011')Returns a single entity directly — no value array wrapper, no paging metadata.
Filter a list
/ProductSkus?$filter=Status eq 'Active'/ProductSkus?$filter=ManufacturerCode eq 'ACME' and Status eq 'Active'Select specific fields
Reduces response size — important for integration scenarios fetching large catalogs:
/ProductSkus?$select=PartNo,Status,ManufacturerCodeExpand related entities
/ProductSkus('100011')?$expand=PriceListsFilter within an expand:
/ProductSkus('100011')?$expand=PriceLists($filter=IsActive eq true)Combine select and expand:
/ProductSkus?$select=PartNo,Status&$expand=PriceLists($select=PriceListCode,PriceSale;$filter=IsActive eq true)Paginate a full catalog export
When exporting all products for an external system, always page through results rather than fetching everything in one request:
/ProductSkus?$select=PartNo,Status&$top=500&$skip=0
/ProductSkus?$select=PartNo,Status&$top=500&$skip=500
/ProductSkus?$select=PartNo,Status&$top=500&$skip=1000Or follow @odata.nextLink from each response automatically.
Look up by external code
A common integration pattern — check whether a product exists in Norce before importing:
/ProductSkus?$filter=IntegrationPartNo eq 'ERP-12345'&$select=PartNo,StatusFetch a group of items in one call
Use the in operator to fetch multiple known items in a single request instead of looping and making one request per item:
/ProductSkus?$filter=PartNo in ('100011', '100012', '100013')This is the preferred pattern when you have a list of identifiers to look up — for example, checking the current status of a batch of products after an import.
Filter by date
Dates must be in ISO 8601 format with timezone. Use gt, lt, ge, le for comparisons:
/Orders?$filter=OrderDate gt 2024-04-01T00:00:00.00Z/Orders?$filter=OrderDate ge 2024-01-01T00:00:00.00Z and OrderDate lt 2024-04-01T00:00:00.00ZFilter on related collections using lambda expressions
Use any to match entities where at least one related item meets a condition, and all to require every related item to meet a condition.
Match products that have a specific active price list:
/ProductSkus?$filter=PriceLists/any(p: p/PriceListId eq 4 and p/IsActive eq true)Match products that have no parametric with a specific ID:
/ProductSkus?$filter=Parametrics/all(p: p/ParametricId ne 42)Combine with other filters:
/ProductSkus?$filter=Status eq 'Active' and PriceLists/any(p: p/PriceListCode eq 'CAMPAIGN' and p/IsActive eq true)&$select=PartNo,StatusBest practices for integrations
- Use
$selectwhenever possible. Fetching only the fields you need significantly reduces response size and query time, especially over large catalogs. - Look up single entities by key rather than filtering.
/ProductSkus('100011')is faster than/ProductSkus?$filter=PartNo eq '100011'when you already know the key. - Cache aggressively in your integration. The Query API is a direct database window with no caching layer. If your integration needs the same data repeatedly, cache it locally rather than re-querying.
- Do not use Query for real-time storefront requests. Use the Norce Commerce Application API for end-user facing requests — it is cached and optimized for that purpose.