Skip to main content

Querying Prices

This guide covers everything you need to make price queries against the Quantaprice engine: choosing between the GET and POST endpoints, constructing pricelist filters, handling currency and VAT, quantity breaks, historical lookups, and reading the response.

All requests require a bearer token obtained from the auth server. See Authentication for details.

Base URL: https://api.quantaprice.com


The two query shapes

Single-SKU GET — point lookups

GET /price/{sku}/{pricelist}
GET /price/{sku}/{pricelist}/{tax_area}

Use these for point lookups where you already know the exact SKU and pricelist code. The engine skips filter resolution and returns a single price record directly, making this the fastest path available.

# Price without VAT
curl -X GET "https://api.quantaprice.com/price/SKU-CHAIR-001/retail-sek" \
-H "Authorization: Bearer $TOKEN"

# Price with VAT for a specific tax area
curl -X GET "https://api.quantaprice.com/price/SKU-CHAIR-001/retail-sek/SE" \
-H "Authorization: Bearer $TOKEN"

When to use the GET endpoints:

  • Server-side rendering of a single product detail page where the pricelist is already known
  • Admin tooling and internal dashboards
  • Audit scripts that walk a known SKU/pricelist matrix

When not to use the GET endpoints: any time you need to match a customer to the right pricelist, query multiple SKUs in one round-trip, or apply best-price selection across several pricelists. Use POST /price/query for all of those.


Batch POST — product pages and carts

POST /price/query accepts multiple SKUs and a pricelist filter, and returns one result per matched (SKU, pricelist) combination. This is the correct endpoint for storefront product listings, cart pricing, and any scenario where you need the engine to resolve which pricelists apply.

curl -X POST "https://api.quantaprice.com/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001", "SKU-DESK-042", "SKU-LAMP-007"],
"pricelist_filter": {
"pricelists": ["customer-acme"]
},
"currency_code": "SEK",
"tax_area": "SE"
}'

The response is a JSON object with a results array ordered by SKU, then by pricelist. If the filter matches multiple pricelists for the same SKU, see Best-price selection below.


Building a pricelist filter

The pricelist_filter object controls which pricelists the engine considers. The three filter keys are pricelists, metadata, and currency_code. You can use any combination; the engine intersects all conditions.

By pricelist code

The most explicit option. Pass an array of pricelist codes:

curl -X POST "https://api.quantaprice.com/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001"],
"pricelist_filter": {
"pricelists": ["customer-acme", "wholesale-tier-1"]
},
"currency_code": "SEK"
}'

A single code in the array bypasses best-price selection and returns exactly that pricelist's price. Useful when the customer's pricelist assignment is resolved upstream (for example, by your CRM or the Shopify adapter) before the query is made.

By metadata

Pricelists carry arbitrary key-value metadata you define in the dashboard. Query by metadata to resolve pricing by customer segment, region, or any other classification without hardcoding pricelist codes in your application:

curl -X POST "https://api.quantaprice.com/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001", "SKU-DESK-042"],
"pricelist_filter": {
"metadata": {
"segment": "wholesale",
"region": "nordics"
}
},
"currency_code": "EUR"
}'

All metadata conditions must match (AND semantics). The engine returns prices from every pricelist that carries all the specified key-value pairs. If multiple pricelists match, best-price selection applies automatically.

By currency

Filter to pricelists denominated in a specific currency. Combine with metadata or pricelist codes to narrow further:

curl -X POST "https://api.quantaprice.com/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001"],
"pricelist_filter": {
"metadata": {"segment": "retail"},
"currency_code": "EUR"
},
"currency_code": "EUR"
}'

Note the distinction: pricelist_filter.currency_code filters which pricelists to consider; the top-level currency_code sets the output currency of the response. They can differ — see Currency and VAT.


Currency and VAT

Requesting an output currency

Set the top-level currency_code to the currency you want prices returned in. If the matched pricelist is denominated in a different currency, the engine applies FX conversion using its internal exchange rates.

# Pricelist is in EUR, response requested in SEK
curl -X POST "https://api.quantaprice.com/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001"],
"pricelist_filter": {
"pricelists": ["wholesale-eur"]
},
"currency_code": "SEK"
}'

Exchange rates are updated daily. For financial reconciliation, use as_of to pin the query to a specific date and ensure reproducible results.

VAT calculation

Include tax_area to receive VAT-inclusive prices alongside the NET price. The engine applies the VAT rate configured for that tax area.

curl -X POST "https://api.quantaprice.com/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001"],
"pricelist_filter": {
"pricelists": ["retail-sek"]
},
"currency_code": "SEK",
"tax_area": "SE"
}'

Response fields when tax_area is provided:

FieldDescription
sales_price_ex_vatNET price (excluding VAT) in the requested currency
sales_price_inc_vatGROSS price (including VAT) in the requested currency
vat_rateDecimal VAT rate applied, e.g. 0.25 for 25%

When tax_area is omitted, sales_price_inc_vat and vat_rate are null. sales_price_ex_vat is always returned.


Quantity breaks

Pass qty to activate quantity-break pricing. The engine selects the tier whose minimum quantity is less than or equal to qty and returns that tier's price.

curl -X POST "https://api.quantaprice.com/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001"],
"pricelist_filter": {
"pricelists": ["wholesale-tier-1"]
},
"currency_code": "SEK",
"tax_area": "SE",
"qty": 25
}'

If qty is below all configured break thresholds, the engine returns the base price. If qty is omitted, base pricing applies.


Historical queries

Use as_of to query prices as they stood at a past point in time. Pass an ISO 8601 UTC timestamp:

curl -X POST "https://api.quantaprice.com/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001"],
"pricelist_filter": {
"pricelists": ["customer-acme"]
},
"currency_code": "SEK",
"as_of": "2025-01-15T00:00:00Z"
}'

Use cases for as_of:

  • Audit trails: Reproduce the exact price a customer was quoted on a given date.
  • Dispute resolution: Confirm what price was active at the time of an order without relying on order snapshots.
  • Debugging price changes: Identify exactly when a price changed by stepping through dates.

Use as_of together with count and took in the response to verify reproducible results.


Best-price selection

When pricelist_filter matches more than one pricelist for the same SKU, the engine does not return all candidates. Instead it:

  1. Normalises every candidate price to NET in the target currency (applying FX conversion as needed).
  2. Returns the single lowest-price candidate.

This is the intended behaviour for B2B scenarios where a customer qualifies for multiple discounts or price tiers and should always receive their best available price.

# Customer qualifies for both wholesale-tier-1 and promo-summer-2025.
# Engine returns whichever is cheaper.
curl -X POST "https://api.quantaprice.com/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001"],
"pricelist_filter": {
"pricelists": ["wholesale-tier-1", "promo-summer-2025"]
},
"currency_code": "SEK"
}'

To opt out of best-price selection, pass exactly one pricelist code. The engine returns that pricelist's price directly without comparison:

"pricelist_filter": {
"pricelists": ["wholesale-tier-1"]
}

Response fields

The response is a JSON object with a results array. Each element corresponds to one (SKU, pricelist) result returned by the engine.

{
"results": [
{
"sku": "SKU-CHAIR-001",
"is_bundle": false,
"sales_price_inc_vat": 389.00,
"sales_price_ex_vat": 311.20,
"vat_rate": 0.25,
"vat_amount": 77.80
}
],
"count": 1,
"took": 3
}

Top-level fields

FieldTypeDescription
skustringThe SKU as supplied in the request.
is_bundlebooleantrue if the SKU is a bundle article.
sales_price_ex_vatnumberPrice excluding VAT in the requested currency. Always present.
sales_price_inc_vatnumber | nullPrice including VAT. Present only when tax_area was supplied.
vat_ratenumber | nullDecimal VAT rate, e.g. 0.25. Present only when tax_area was supplied.
vat_amountnumber | nullVAT amount in currency. Present only when tax_area was supplied.

See also

  • VAT — how tax areas and VAT classes are configured.
  • Bundles — how bundle prices appear in query responses.
  • Rounding — rounding profiles and the rounding_profile query parameter.
  • OpenAPI Reference — full machine-readable spec.