Last updated

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/$metadata

Limits

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

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,ManufacturerCode
/ProductSkus('100011')?$expand=PriceLists

Filter 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=1000

Or 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,Status

Fetch 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.00Z

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,Status

Best practices for integrations

  • Use $select whenever 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.

Further reading