Een product heeft één SKU, een lijstprijs en optionele merk, categorie, voorraadstatus en extra details. Prijzen worden altijd voor u berekend: zie Prices.
Producten kunnen ook familyId en orderStep hebben (standaard 1). Een enkelvoudige productlezing bevat optionele family metadata met zijn naam, variantattribuutnamen en instelling. Een geconfigureerde prijs bevat orderingFields, configurationRequired, definitionVersion en optionele klantgeprijsde quantityBreaks. Volgordes velden zijn koperinput; details blijven productfeiten.
POST/api/v1/products/{id}/quote
Deze alleen-lezen bewerking accepteert { "customer": "ACME01", "qty": 3, "configuration": { "length": 2.75, "reference": "Kitchen" } }. customer is optioneel voor medewerkerslijstprijzen. Alleen-lezen sleutels kunnen het gebruiken. Het retourneert data.productId, qty, gevalideerde fields, definitionVersion en price met unit, line en de gekozen specificatie. Ontbrekende verplichte velden retourneren Configureer voor prijs; ongeldige combinaties worden geweigerd. Het maakt geen mandje, bestelling of betaling aan. Gebruik price.line in plaats van de eenheidsprijs te vermenigvuldigen.
Imports accepteren optionele family, orderStep en orderingDefinition. Een definitie gebruikt het schema in OpenAPI, vereist Pro en globale prijsrechten, en retourneert ruleDrafts voor review via de bestaande prijswijzigingsworkflow. Ontbrekende structuur laat bestaande instellingen onveranderd. Zie trade catalogue setup.
Het productobjectLink naar deze sectie#
{
"id": "3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c",
"sku": "HX-8510",
"name": "Hex bolt M10 x 50 zinc",
"description": "Grade 8.8, zinc plated, fully threaded.",
"brandId": "a1b2c3d4-0000-4000-8000-000000000001",
"categoryId": "a1b2c3d4-0000-4000-8000-000000000002",
"manufacturerRef": "DIN933-M10-50",
"unitLabel": "Box of 100",
"minOrderQty": 1,
"availability": "in_stock",
"stockQty": 240,
"lowStockAt": null,
"leadTimeNote": null,
"dealText": null,
"active": true,
"visibility": "all",
"details": { "Finish": "Zinc", "Thread": "M10" },
"createdAt": "2026-08-14T09:30:00.000Z",
"updatedAt": "2026-09-20T16:02:11.000Z",
"price": {
"unit": 1850,
"line": 1850,
"list": 1850,
"discountBp": 0,
"source": "list",
"label": ""
}
}
| Veld | Type | Beschrijving |
|---|---|---|
id | string | Product id. |
sku | string | Uw voorraadcode. Uniek in de werkruimte, hoofdletteronafhankelijk. |
name | string | Productnaam. |
description | string of null | Langere beschrijving. |
brandId, categoryId | string of null | Zie merken en categorieën. |
manufacturerRef | string of null | Artikelnummer van de fabrikant. Zoekbaar zoals de SKU. |
unitLabel | string | Wat één eenheid is, bijvoorbeeld “Stuk” of “Doos met 100”. |
minOrderQty | integer | Kleinst mogelijke hoeveelheid die kopers kunnen bestellen. |
availability | string | not_tracked, in_stock, low_stock, out_of_stock of made_to_order. Een label voor kopers alleen: elk product kan besteld worden. Het verzenden zonder stockQty verwijdert elke opgeslagen hoeveelheid (je stelt de status handmatig in). Met een stockQty berekent het voor je: 0 of minder is out_of_stock, tot het laag niveau is low_stock, boven dat is in_stock. made_to_order wordt nooit veranderd door het aantal. |
stockQty | integer of null | Aantal op voorraad, of null als je dit product niet telt. Wanneer ingesteld, volgt availability hierop. Niet opgenomen wanneer je als klant vraagt (customer). |
lowStockAt | integer of null | Dit product’s eigen laag voorraadniveau, of null om het werkplek niveau te gebruiken. Niet opgenomen wanneer je als klant vraagt. |
leadTimeNote | string of null | Bijv. “3–5 werkdagen”. |
dealText | string of null | Een opmerking naast de prijs, zoals “min 12 btls 45”. De titel is het deal-label van de werkplek (Instellingen, Catalogusweergave). |
active | boolean | Inactieve producten zijn verborgen voor kopers. |
visibility | string | all, of selected wanneer alleen geselecteerde klanten het kunnen zien. |
details | object | Extra kolommen van importen, zoals { "Finish": "Zinc" }. |
price | object of null | De prijs bij hoeveelheid 1 (of qty). Zie Prijzen. unit is null wanneer het product nog geen prijs heeft. |
Stockaantallen zijn van u om up-to-date te houden: bestellingen veranderen nooit stockQty, dus stuur het vanuit uw stocksystem wanneer het verandert. Klanten zien alleen de availability status, nooit het aantal. Bij nul kan een product nog steeds besteld worden; het is gewoon gemarkeerd als uit voorraad.
GET /products/{id} bevat ook de namen brand en category.
Afbeeldingen worden niet geretourneerd door de API. U kunt er een instellen met imageUrl bij het aanmaken of bijwerken.
Producten lijsten of zoekenLink naar deze sectie#
GET/api/v1/products
Zonder q worden producten op naam gelijst. Met q komen de resultaten in deze volgorde:
- exacte SKU of fabrikantreferentie
- SKU of fabrikantreferentie die begint met
q - volledige tekst matches op naam, merk, categorie en beschrijving (3 of meer tekens; kortere zoekopdrachten matchen het begin van de naam)
Geef customer door om elke rij voor die klant te prijzen en retourneer alleen producten die die klant kan zien (actief, en ofwel voor iedereen of gekozen voor hen). Dat is precies wat de klant ziet in hun handelsportaal.
| Naam | Type | Verplicht | Beschrijving |
|---|---|---|---|
q | string | niet | SKU, fabrikantreferentie, naam, merk of categorie. Maximaal 200 tekens. |
category | string | niet | Categorie id. |
brand | string | niet | Merk id. |
availability | string | niet | Een van de beschikbaarheidswaarden. |
active | true of false | niet | true retourneert alleen actieve producten. Standaard is true als customer is ingesteld; anders worden alle producten geretourneerd. |
customer | string | niet | Klant id of accountcode. |
limit | integer | niet | 1 tot 50. Standaard 50. |
offset | integer | niet | Rijen om te overslaan. Standaard 0. |
curl "https://tradecatalog.app/api/v1/products?q=hex%20bolt&customer=OAK01&limit=20" \
-H "Authorization: Bearer $TRADECATALOG_API_KEY"
const params = new URLSearchParams({
q: 'hex bolt',
customer: 'OAK01',
limit: '20',
})
const res = await fetch(`https://tradecatalog.app/api/v1/products?${params}`, {
headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` },
})
const { data: products, nextOffset } = await res.json()
{
"data": [
{
"id": "3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c",
"sku": "HX-8510",
"name": "Hex bolt M10 x 50 zinc",
"description": "Grade 8.8, zinc plated, fully threaded.",
"brandId": "a1b2c3d4-0000-4000-8000-000000000001",
"categoryId": "a1b2c3d4-0000-4000-8000-000000000002",
"manufacturerRef": "DIN933-M10-50",
"unitLabel": "Box of 100",
"minOrderQty": 1,
"availability": "in_stock",
"leadTimeNote": null,
"active": true,
"visibility": "all",
"details": { "Finish": "Zinc", "Thread": "M10" },
"createdAt": "2026-08-14T09:30:00.000Z",
"updatedAt": "2026-09-20T16:02:11.000Z",
"price": {
"unit": 1573,
"line": 1573,
"list": 1850,
"discountBp": 1500,
"source": "brand",
"label": "Brand discount −15%"
}
}
],
"nextOffset": null,
"currency": "GBP"
}
Een product ophalenLink naar deze sectie#
GET/api/v1/products/{id}
| Naam | In | Type | Verplicht | Beschrijving |
|---|---|---|---|---|
id | path | string | ja | Product id. |
customer | query | string | niet | Klant id of accountcode. Retourneert 404 als die klant het product niet kan zien. |
qty | query | integer | niet | Hoeveelheid om te prijzen, 1 tot 1.000.000. Standaard 1. price.line is unit × qty. |
curl "https://tradecatalog.app/api/v1/products/3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c?customer=OAK01&qty=5" \
-H "Authorization: Bearer $TRADECATALOG_API_KEY"
const res = await fetch(
`https://tradecatalog.app/api/v1/products/${productId}?customer=OAK01&qty=5`,
{ headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` } },
)
const { data: product } = await res.json()
{
"data": {
"id": "3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c",
"sku": "HX-8510",
"name": "Hex bolt M10 x 50 zinc",
"description": "Grade 8.8, zinc plated, fully threaded.",
"brandId": "a1b2c3d4-0000-4000-8000-000000000001",
"categoryId": "a1b2c3d4-0000-4000-8000-000000000002",
"manufacturerRef": "DIN933-M10-50",
"unitLabel": "Box of 100",
"minOrderQty": 1,
"availability": "in_stock",
"leadTimeNote": null,
"active": true,
"visibility": "all",
"details": { "Finish": "Zinc", "Thread": "M10" },
"createdAt": "2026-08-14T09:30:00.000Z",
"updatedAt": "2026-09-20T16:02:11.000Z",
"brand": "Northgate",
"category": "Bolts",
"price": {
"unit": 1573,
"line": 7865,
"list": 1850,
"discountBp": 1500,
"source": "brand",
"label": "Brand discount −15%"
}
},
"currency": "GBP"
}
Gebruik GET /products?q=HX-8510 om een product op SKU te zoeken: een exacte SKU-match komt altijd eerst. Gebruik ook GET /prices, wat een SKU neemt.
Producten aanmaken of bijwerkenLink naar deze sectie#
PUT/api/v1/productsschrijf sleutel
Stuur maximaal 100 producten per oproep. Elk wordt matched met een bestaand product via de SKU, ongeacht hoofdletters. Als er geen match is, wordt een nieuw product aangemaakt. Merken en categorieën worden matched op naam en aangemaakt als ze niet bestaan.
Hoe lijsprijzen worden behandeldLink naar deze sectie#
| Het product... | Wat gebeurt er met de prijs |
|---|---|
| is nieuw | Gaat live op listPrice direct. |
| bestaat maar heeft nog geen prijs | Gaat live op listPrice direct. |
| bestaat met dezelfde prijs | Niets. |
| bestaat met een andere prijs | Niets verandert nog. De nieuwe prijs gaat in een conceptprijsverandering voor die lijst. priceChangeId is het concept voor de lijst van listPrice. priceChangesByList heeft één entry per lijst die veranderde. |
Conceptprijsveranderingen zijn hoe TradeCatalog een typfout voorkomt bij klanten. De eigenaar of medewerkers bekijken het concept in de app (Prijsveranderingen), controleren de grootste bewegingen en waarschuwingen, kiezen een datum en of klanten moeten worden geëmaild, en publiceren het. U kunt een concept bekijken met GET /price-changes/{id}.
Eén synchronisatie, één concept per lijst
Een oproep die prijzen verandert start een concept per lijst, genaamd “API import (sleutelnaam)” voor Standard en met de lijstnaam wanneer u meer dan één stuurt. Om een hele synchronisatie in die concepten te houden, stuur priceChangeId (de lijst voor listPrice) en drafts (de andere lijsten) van de eerste oproep met elke latere oproep. Elke moet nog steeds een concept zijn: zodra het gepubliceerd, geannuleerd of weggegooid is, laat dat id weg om een nieuw one te starten.
LichaamLink naar deze sectie#
| Veld | Type | Verplicht | Beschrijving |
|---|---|---|---|
products | array | ja | 1 tot 100 producten. SKUs moeten uniek zijn binnen de oproep. |
priceChangeId | string | nee | Een concept voor de listPrice-lijst van een vorige oproep. Gewijzigde prijzen voor die lijst worden er aan toegevoegd. 404 als het niet bestaat, 400 als het geen concept meer is. |
drafts | array | nee | Maximaal 30 { list, priceChangeId }-vermeldingen zodat andere lijsten hun eigen concepten kunnen voortzetten. |
products[].sku | string | ja | Maximaal 64 tekens. |
products[].name | string | ja | Maximaal 200 tekens. |
products[].listPrice | integer of null | ja | Minder eenheden, 0 tot 1.000.000.000. null is prijs op verzoek: een nieuw product heeft geen prijs, een bestaand product behoudt de zijne. |
products[].priceList | string of null | nee | Naam van een bestaande prijslijst voor listPrice. Weglaten of null is Standard. Een onbekende naam wordt afgewezen. |
products[].listPrices | array | nee | Andere lijsten, zoals { list, price }. price is minder eenheden, of null om die lijst onveranderd te laten. Een onbekende naam wordt afgewezen. |
products[].unitLabel | string | ja | Maximaal 60 tekens, bijvoorbeeld “Stuk”. |
products[].brand | string | nee | Merknaam, maximaal 120 tekens. Gecleard als deze wordt weggelaten. |
products[].category | string | nee | Categorienaam, maximaal 120 tekens. Gecleard als deze wordt weggelaten. |
products[].manufacturerRef | string | nee | Maximaal 120 tekens. Gecleard als deze wordt weggelaten. |
products[].description | string | nee | Maximaal 4.000 tekens. Gewisig als deze ontbreekt. |
products[].availability | string | nee | Een van de beschikbaarheidswaarden. Behouden als deze ontbreekt; nieuwe producten beginnen als not_tracked. |
products[].stockQty | geheel getal of null | nee | Voorraadhoeveelheid, van -1.000.000 tot 1.000.000.000. Stelt availability in (zie het productobject); een status die u erbij stuurt wordt genegeerd, behalve made_to_order. Behouden als deze ontbreekt, tenzij u een availability zonder deze stuurt: dan wordt het aantal gewist en wordt die status gebruikt. null stopt met tellen; de availability die in dezelfde rij wordt gestuurd, geldt, of de huidige status als er geen is. |
products[].lowStockAt | geheel getal of null | nee | Laag voorraadniveau voor dit product, van 0. null gebruikt het werkruimteniveau (Instellingen, 5 om te beginnen). Behouden als deze ontbreekt. |
products[].leadTimeNote | string | nee | Maximaal 200 tekens. Behouden als deze ontbreekt. |
products[].dealText | string | nee | Maximaal 200 tekens, weergegeven naast de prijs. Behouden als deze ontbreekt. |
products[].details | object | nee | Maximaal 30 extra kolommen: namen tot 60 tekens, waarden tot 500. Vervangt alle details wanneer gestuurd; behouden als deze ontbreekt. |
products[].imageUrl | string | nee | Een https afbeeldings-URL. Kopieert naar TradeCatalog op de achtergrond wanneer het verandert. Behouden als deze ontbreekt. |
products[].onlyFor | array | nee | Maximaal 200 accountcodes of contactmails. Maakt het product zichtbaar alleen voor die klanten, in plaats van een vorige lijst. Behouden als deze ontbreekt. |
Stuur elke veld dat je belangrijk vindt
brand, category, manufacturerRef en description worden zoals verstuurd geschreven, dus als u er een laatste, wordt deze gewist. Stuur het volledige product elke keer, zoals een spreadsheetrij.
Deze kunnen nog niet worden gewijzigd via de API: een product inactief maken, minOrderQty, een afbeelding verwijderen, een leadtime-notitie wissen en een klant-alleen product opnieuw zichtbaar maken voor iedereen. Doe dit in de app.
curl -X PUT https://tradecatalog.app/api/v1/products \
-H "Authorization: Bearer $TRADECATALOG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"products": [
{
"sku": "HX-8510",
"name": "Hex bolt M10 x 50 zinc",
"listPrice": 1950,
"unitLabel": "Box of 100",
"brand": "Northgate",
"category": "Bolts",
"manufacturerRef": "DIN933-M10-50",
"availability": "in_stock",
"details": { "Finish": "Zinc", "Thread": "M10" }
},
{
"sku": "OAK-HNG-75",
"name": "Oak-finish butt hinge 75mm",
"listPrice": 695,
"unitLabel": "Pair",
"category": "Hinges",
"onlyFor": ["OAK01"]
}
]
}'
const res = await fetch('https://tradecatalog.app/api/v1/products', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ products }),
})
const { data: result } = await res.json()
if (result.priceChangeId)
console.log('Review the draft price change in TradeCatalog')
{
"data": {
"created": 1,
"updated": 1,
"priceChanges": 1,
"priceChangeId": "c4d5e6f7-1234-4abc-9def-0123456789ab",
"priceChangesByList": [
{
"list": "Standard",
"priceChangeId": "c4d5e6f7-1234-4abc-9def-0123456789ab"
}
],
"unknownCustomers": []
}
}
| Veld | Beschrijving |
|---|---|
created | Nieuwe producten. |
updated | Bestaande producten die overeenkomen met SKU. |
priceChanges | Hoeveel prijzen zijn opgenomen in een concept, over elk lijst in de oproep. |
priceChangeId | Het concept voor de listPrice-lijst, of null als die lijst geen wijzigingen had. |
priceChangesByList | Een { list, priceChangeId } voor elke lijst die in deze oproep een prijswijziging had. |
unknownCustomers | Waarden in onlyFor die geen klant hebben gevonden (maximaal 50). Die klanten kregen geen toegang. |
Veranderingen verschijnen in de activiteitenlog als de naam van de sleutel, en zoekopdrachten worden direct bijgewerkt.
Merken en categorieënLink naar deze sectie#
GET/api/v1/brands
GET/api/v1/categories
Beide retourneren elke rij, gesorteerd op naam, zonder paginering. Gebruik de ids met de filters brand en category op GET /products.
curl https://tradecatalog.app/api/v1/categories \
-H "Authorization: Bearer $TRADECATALOG_API_KEY"
const res = await fetch('https://tradecatalog.app/api/v1/categories', {
headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` },
})
const { data: categories } = await res.json()
{
"data": [
{ "id": "a1b2c3d4-0000-4000-8000-000000000002", "name": "Bolts" },
{ "id": "a1b2c3d4-0000-4000-8000-000000000003", "name": "Hinges" }
]
}
Om een merk of categorie te maken, noem het op een product in PUT /products.