Querying Prices
This guide covers price queries against the Quantaprice engine: the GET and POST endpoints, pricelist filters, currency and VAT, quantity breaks, historical lookups, and the response.
All requests require a bearer token obtained from the auth server. See Authentication for details.
Base URL: https://YOUR_TENANT.quantaprice.com/api, where YOUR_TENANT is your tenant's name as shown in the account dashboard.
The two query shapes
Single-SKU GET: point lookups
GET /price/{sku}/{pricelist}
GET /price/{sku}/{pricelist}/{tax_area}
Use these for point lookups when you already know the exact SKU and pricelist code. The engine skips pricelist selection and returns that one price, which makes this the fastest path. The form with {tax_area} also returns the VAT-inclusive price.
# The stored price
curl "https://YOUR_TENANT.quantaprice.com/api/price/SKU-CHAIR-001/retail-sek" \
-H "Authorization: Bearer $TOKEN"
# The price with VAT for a tax area
curl "https://YOUR_TENANT.quantaprice.com/api/price/SKU-CHAIR-001/retail-sek/SE" \
-H "Authorization: Bearer $TOKEN"
Use the GET endpoints for:
- Server-side rendering of a single product page where the pricelist is already known
- Admin tooling and internal dashboards
- Audit scripts that walk a known SKU/pricelist matrix
Do not use them when you need to match a customer to the right pricelist, price several SKUs in one round trip, or pick the best price across several pricelists. Use POST /price/query for all of those.
Batch POST: product pages and carts
POST /price/query prices many SKUs at once against a pricelist filter. It is the endpoint for storefront listings, cart pricing, and any case where the engine should work out which pricelists apply.
curl -X POST "https://YOUR_TENANT.quantaprice.com/api/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"
}'
Request fields
| Field | Required | Description |
|---|---|---|
skus | yes | The SKUs to price. Not empty. |
pricelist_filter | yes | Which pricelists to consider; see Building a pricelist filter. |
currency_code | yes | The currency prices are returned in. |
tax_area | yes | The tax area whose VAT rates apply, for example SE. |
as_of | no | ISO 8601 instant to price at; default now. See Historical queries. |
rounding_profile | no | Rounding profile to apply; see Rounding. |
sort_order | no | ASC or DESC: order results by price ex VAT. Default: the order of skus. |
A request missing any of the required fields, or with an empty value for one, gets 400 Bad Request.
The response has one result per SKU that has a price. SKUs without a price in any selected pricelist are left out, so compare count with the number of SKUs you sent.
Building a pricelist filter
pricelist_filter decides which pricelists the engine considers. It has three keys, and at least one must be set:
pricelists: explicit pricelist codes. When given, exactly these pricelists are used and the other two keys are ignored.currency_code: without codes, select every pricelist in this currency.metadata: without codes, select every pricelist whose metadata matches.
Without codes, currency_code and metadata combine: a pricelist must match both.
By pricelist code
The most explicit option:
curl -X POST "https://YOUR_TENANT.quantaprice.com/api/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",
"tax_area": "SE"
}'
A single code returns exactly that pricelist's price. Use one when the customer's pricelist is resolved upstream, for example by your CRM or the Shopify adapter, before the query is made.
By metadata
Pricelists carry key-value metadata you define. Selecting by metadata resolves pricing by customer segment, region, or any other classification without hardcoding pricelist codes in your application. Each key takes a list of accepted values:
curl -X POST "https://YOUR_TENANT.quantaprice.com/api/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", "baltics"]
}
},
"currency_code": "EUR",
"tax_area": "SE"
}'
A pricelist matches when every key holds one of its listed values: here, segment wholesale and region nordics or baltics. When several pricelists match, best-price selection applies.
By currency
Select the pricelists denominated in one currency, optionally narrowed by metadata:
curl -X POST "https://YOUR_TENANT.quantaprice.com/api/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",
"tax_area": "DE"
}'
Note the distinction: pricelist_filter.currency_code selects pricelists, while the top-level currency_code sets the currency of the response. They can differ; see Currency and VAT.
Currency and VAT
Output currency
The top-level currency_code is the currency prices are returned in. When a selected pricelist is in another currency, the engine converts with its exchange rates.
# The pricelist is in EUR; prices come back in SEK
curl -X POST "https://YOUR_TENANT.quantaprice.com/api/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001"],
"pricelist_filter": {
"pricelists": ["wholesale-eur"]
},
"currency_code": "SEK",
"tax_area": "SE"
}'
Exchange rates are updated daily. For financial reconciliation, use as_of to pin the query to a point in time so the result is reproducible.
VAT
tax_area is required. Every result carries the price both excluding and including VAT, calculated with the VAT rate of that tax area:
| Field | Description |
|---|---|
sales_price_ex_vat | Price excluding VAT, in the requested currency |
sales_price_inc_vat | Price including VAT, in the requested currency |
vat_amount | The VAT, in the requested currency |
vat_rate | The VAT rate applied, in percent: 25.0 for 25% |
Quantity breaks
A price query has no quantity parameter. Each result carries the base price, and its price.quantity_breaks lists every quantity break of the winning pricelist, already converted and with VAT applied. Use the break with the highest quantity_break that does not exceed your quantity. Below the lowest break, or when the list is empty, the base price applies.
"quantity_breaks": [
{ "quantity_break": 10, "sales_price_ex_vat": 280.00, "sales_price_inc_vat": 350.00, "vat_amount": 70.00 },
{ "quantity_break": 50, "sales_price_ex_vat": 249.60, "sales_price_inc_vat": 312.00, "vat_amount": 62.40 }
]
Historical queries
Use as_of to price as of a past moment. Pass an ISO 8601 timestamp:
curl -X POST "https://YOUR_TENANT.quantaprice.com/api/price/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skus": ["SKU-CHAIR-001"],
"pricelist_filter": {
"pricelists": ["customer-acme"]
},
"currency_code": "SEK",
"tax_area": "SE",
"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 which price was active when an order was placed, without relying on order snapshots.
- Debugging price changes: find when a price changed by stepping through dates.
Best-price selection
When the filter selects more than one pricelist with a price for the same SKU, the engine returns one result per SKU, not one per pricelist. It:
- Normalises every candidate to a price excluding VAT in the requested currency, applying FX conversion as needed.
- Returns the lowest.
price.pricelist in the result says which pricelist won. This is the intended behaviour for B2B, where a customer who qualifies for several discounts or price tiers should always get the best one.
# The customer qualifies for both wholesale-tier-1 and promo-summer-2025;
# the engine returns whichever is cheaper.
curl -X POST "https://YOUR_TENANT.quantaprice.com/api/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",
"tax_area": "SE"
}'
To opt out of best-price selection, pass exactly one pricelist code.
Response
{
"count": 1,
"results": [
{
"sku": "SKU-CHAIR-001",
"is_bundle": false,
"sales_price_ex_vat": 311.20,
"sales_price_inc_vat": 389.00,
"vat_amount": 77.80,
"vat_rate": 25.0,
"price": {
"pricelist": "customer-acme",
"currency_code": "SEK",
"sales": 311.20,
"fields": { "fixed": 311.20 },
"quantity_breaks": [],
"meta": {
"inherited": false,
"start_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z",
"updated_by": "erp-sync"
}
}
}
]
}
| Field | Type | Description |
|---|---|---|
count | number | Number of results: the SKUs that have a price. |
results[].sku | string | The SKU as sent in the request. |
results[].is_bundle | boolean | true when the SKU is a bundle article; see Bundles. |
results[].sales_price_ex_vat | number | Price excluding VAT, in the requested currency. |
results[].sales_price_inc_vat | number | Price including VAT, in the requested currency. |
results[].vat_amount | number | The VAT, in the requested currency. |
results[].vat_rate | number | VAT rate in percent, e.g. 25.0. |
results[].price.pricelist | string | The pricelist the price comes from (the winner, with several candidates). |
results[].price.currency_code | string | The currency of price.sales and price.fields. |
results[].price.sales | number | The pricelist's price in its own currency, after price rules, before conversion and VAT. |
results[].price.fields | object | The price's stored fields. |
results[].price.quantity_breaks | array | The pricelist's quantity breaks, resolved like the base price; see Quantity breaks. |
results[].price.meta | object | When the price took effect, when it was last updated and by whom, and whether it was inherited from a parent pricelist. |
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_profilefield. - Rate Limits: what a price query costs against your query limit.
- API Reference: every endpoint.