TradeCatalog works out every customer price in one place, the same way for the app, the trade portal, MCP and the API. You never calculate prices yourself.
How prices are worked outLink to this section#
The most specific rule wins, and discounts never stack:
- Agreed price. If the customer has an agreed (fixed) price for the product, that’s the price.
- Otherwise the list price minus one percentage, the first that applies:
- the customer’s discount for the product’s category
- the customer’s discount for the product’s brand
- the customer’s own account discount
- Otherwise the list price.
A category rule of 10% and an account discount of 5% give 10% off, not 15%.
The discounted unit price is rounded half up to a whole minor unit. The line total is unit × qty, so a line never has fractions of a penny.
List prices and agreed prices are versioned by date. The API always gives the price valid now. Future prices from a scheduled price change apply from their date.
The price objectLink to this section#
Every product’s price has this shape. GET /prices returns the same fields at the top level of data.
{
"unit": 1573,
"line": 15730,
"list": 1850,
"discountBp": 1500,
"source": "brand",
"label": "Brand discount −15%"
}
| Field | Type | Description |
|---|---|---|
unit | integer or null | Price for one unit, in minor units. null if the product has no price. |
line | integer or null | unit × qty. |
list | integer or null | The list price now. |
discountBp | integer | The discount applied, in basis points. 0 for agreed and list prices. |
source | string | Which rule set the price: see below. |
label | string | Wording buyers see next to the price. |
source | Meaning | Example label |
|---|---|---|
fixed | The customer’s agreed price | Agreed price |
category | Category discount | Category discount −12.5% |
brand | Brand discount | Brand discount −15% |
account | The customer’s own discount | Your discount −5% |
list | List price, no discount | (empty) |
unpriced | The product has no price yet | (empty) |
Check a customer priceLink to this section#
GET/api/v1/prices
What a customer pays for one SKU at a quantity, and why. Use it to answer “what does Oakfield pay for 10 boxes of HX-8510?”.
| Name | Type | Required | Description |
|---|---|---|---|
customer | string | yes | Customer id or account code. |
sku | string | yes | The SKU, ignoring case. |
qty | integer | no | 1 to 1,000,000. Default 1. |
curl "https://tradecatalog.app/api/v1/prices?customer=OAK01&sku=HX-8510&qty=10" \
-H "Authorization: Bearer $TRADECATALOG_API_KEY"
const params = new URLSearchParams({
customer: 'OAK01',
sku: 'HX-8510',
qty: '10',
})
const res = await fetch(`https://tradecatalog.app/api/v1/prices?${params}`, {
headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` },
})
const { data: price, currency } = await res.json()
{
"data": {
"customer": {
"id": "7d2e4f0a-1b3c-4d5e-8f90-a1b2c3d4e5f6",
"accountCode": "OAK01",
"name": "Oakfield Joinery"
},
"sku": "HX-8510",
"name": "Hex bolt M10 x 50 zinc",
"qty": 10,
"unit": 1573,
"line": 15730,
"list": 1850,
"discountBp": 1500,
"source": "brand",
"label": "Brand discount −15%"
},
"currency": "GBP"
}
| Status | Code | When |
|---|---|---|
| 400 | validation_error | customer or sku missing, or qty out of range. |
| 404 | not_found | No such customer, or no product with that SKU. |
This endpoint checks the price only. It doesn’t check whether the customer can see the product. For that, use GET /products/{id}?customer=….
Prices for many productsLink to this section#
To price a whole page of products for one customer, use GET /products?customer=OAK01. Every row’s price is that customer’s price, and customer-only products for other customers are left out. See Products.
Changing pricesLink to this section#
- List prices change through price changes, so customers get notice. Send new prices with
PUT /products; they go into a draft that you publish in the app. - Discounts and agreed prices are set per customer in the app. Read them with
GET /customers/{id}. - A customer’s account discount can be set with
PUT /customers(discountBp).