Um produto tem um SKU, um preço de lista e uma marca, categoria, status de estoque e detalhes adicionais opcionais. Os preços são sempre calculados para você: veja Preços.
Os produtos também podem ter familyId e orderStep (padrão 1). Uma leitura de um único produto inclui metadados opcionais family com seu nome, nomes de atributos de variante e predefinição. Um preço configurado contém orderingFields, configurationRequired, definitionVersion e preço do cliente opcional quantityBreaks. Os campos de ordenação são entradas do comprador; details permanecem como fatos do produto.
POST/api/v1/products/{id}/quote
Esta operação somente leitura aceita { "customer": "ACME01", "qty": 3, "configuration": { "length": 2.75, "reference": "Kitchen" } }. customer é opcional para preços da lista de funcionários. Chaves somente leitura podem usá-lo. Ele retorna data.productId, qty, fields validados, definitionVersion e price com unit, line e a especificação escolhida. Campos obrigatórios ausentes retornam Configurar para preço; combinações inválidas são recusadas. Ele não cria um cesto, pedido ou pagamento. Use price.line em vez de multiplicar o preço unitário.
As importações aceitam os family, orderStep e orderingDefinition opcionais. Uma definição usa o esquema OpenAPI, requer o plano Pro e permissão para precificação global, e retorna o ruleDrafts para revisão por meio do fluxo de trabalho existente de alteração de preço. A estrutura omitida deixa as configurações existentes intactas. Veja configuração do catálogo de comércio.
O objeto do produtoLink para esta seção#
{
"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": ""
}
}
| Campo | Tipo | Descrição |
|---|---|---|
id | string | ID do produto. |
sku | string | Seu código de estoque. Único no espaço de trabalho, ignorando maiúsculas e minúsculas. |
name | string | Nome do produto. |
description | string ou null | Descrição mais longa. |
brandId, categoryId | string ou null | Consulte marcas e categorias. |
manufacturerRef | string ou nulo | Número de peça do fabricante. Pesquisável como o SKU. |
unitLabel | string | O que uma unidade é, por exemplo, “Cada” ou “Caixa de 100”. |
minOrderQty | inteiro | Quantidade mínima que os compradores podem pedir. |
availability | string | not_tracked, in_stock, low_stock, out_of_stock ou made_to_order. Uma etiqueta apenas para compradores: cada produto pode ser comprado. Enviando-o sem um stockQty apaga qualquer contagem armazenada (você está definindo o status manualmente). Com um stockQty é calculado para você: 0 ou menos é out_of_stock, até o nível mínimo é low_stock, acima disso é in_stock. made_to_order nunca é alterado pelo número. |
stockQty | inteiro ou nulo | Unidades em estoque, ou null quando você não contabiliza este produto. Quando definido, availability segue-o. Excluído quando você o solicita como cliente (customer). |
lowStockAt | inteiro ou nulo | Nível de estoque baixo próprio do produto, ou null para usar o nível do espaço de trabalho. Excluído quando você o pede como cliente. |
leadTimeNote | string ou null | ex. “3–5 dias úteis”. |
dealText | string ou nulo | Uma nota exibida ao lado do preço, como "mín 12 btls 45". Seu título é a etiqueta de negócios do espaço de trabalho (Configurações, Exibição do Catálogo). |
active | booleano | Produtos inativos são ocultos dos compradores. |
visibility | string | all, ou selected quando apenas clientes selecionados puderem vê-lo. |
details | object | Colunas adicionais de imports, como { "Finish": "Zinc" }. |
price | objeto ou nulo | O preço na quantidade 1 (ou qty). Veja Preços. unit é null quando o produto não tem preço ainda. |
Contagens de estoque são suas para manter atualizadas: os pedidos nunca mudam stockQty, então envie-o do seu sistema de estoque sempre que houver alterações. Os clientes veem apenas o status availability, nunca o número. Em zero, um produto ainda pode ser pedido; ele simplesmente é rotulado como fora de estoque.
Os nomes GET /products/{id} também incluem brand e category.
Imagens não são retornadas pela API. Você pode definir uma com imageUrl ao criar ou atualizar.
Listar ou pesquisar produtosLink para esta seção#
GET/api/v1/products
Sem q, os produtos são listados por nome. Com q, os resultados aparecem nesta ordem:
- SKU exato ou referência do fabricante
- SKU ou referência do fabricante que começa com
q - correspondências de texto completo no nome, marca, categoria e descrição (3 ou mais caracteres; consultas mais curtas correspondem ao início do nome)
Passe customer para definir o preço de cada linha para esse cliente e retorne apenas os produtos que esse cliente pode ver (ativos e tanto para todos quanto selecionados para eles). Isso é exatamente o que o cliente vê em seu portal comercial.
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
q | string | não | SKU, referência do fabricante, nome, marca ou categoria. Até 200 caracteres. |
category | string | não | ID da categoria. |
brand | string | não | ID da marca. |
availability | string | não | Um dos valores de disponibilidade. |
active | true ou false | não | true retorna apenas produtos ativos. O padrão é true quando customer é definido; caso contrário, todos os produtos são retornados. |
customer | string | não | ID do cliente ou código da conta. |
limit | inteiro | não | 1 a 50. Padrão 50. |
offset | inteiro | não | Linhas a pular. Padrão 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"
}
Obter um produtoLink para esta seção#
GET/api/v1/products/{id}
| Nome | Entrada | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
id | caminho | string | sim | ID do produto. |
customer | consulta | string | não | ID do cliente ou código da conta. Retorna 404 se esse cliente não puder visualizar o produto. |
qty | consulta | inteiro | não | Quantidade a ser precificada, 1 a 1.000.000. Padrão 1. price.line é 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"
}
Para pesquisar um produto pelo SKU, use GET /products?q=HX-8510: uma correspondência exata de SKU sempre aparece em primeiro lugar. Ou use GET /prices, que aceita um SKU.
Criar ou atualizar produtosLink para esta seção#
PUT/api/v1/productsescreva a chave
Envie até 100 produtos por chamada. Cada um é correspondido a um produto existente pelo SKU, ignorando maiúsculas e minúsculas. Se não houver correspondência, um novo produto é criado. Marcas e categorias são correspondidas pelo nome e criadas se não existirem.
Como os preços da lista são tratadosLink para esta seção#
| O produto... | O que acontece com o preço |
|---|---|
| é novo | Fica disponível em listPrice imediatamente. |
| existe, mas ainda não tem preço | Fica disponível em listPrice imediatamente. |
| existe ao mesmo preço | Nada. |
| existe a um preço diferente | Nada muda ainda. O novo preço entra em uma mudança de preço em rascunho para essa lista. priceChangeId é o rascunho para a lista de listPrice. priceChangesByList tem uma entrada por lista que foi alterada. |
Alterações de preço em rascunho são como o TradeCatalog evita que um erro de digitação chegue aos clientes. O proprietário ou funcionários revisam o rascunho no aplicativo (Alterações de preço), verificam as maiores mudanças e alertas, escolhem uma data e se deseja enviar um e-mail aos clientes, e depois publicam. Você pode visualizar um rascunho com GET /price-changes/{id}.
Uma sincronização, um rascunho por lista
Uma chamada que muda preços inicia um rascunho por lista, chamado “Importação de API (nome da chave)” para Standard e com o nome da lista quando você enviar mais de uma. Para manter uma sincronização inteira nesses rascunhos, envie priceChangeId (a lista para listPrice) e drafts (as outras listas) da primeira chamada com cada chamada posterior. Cada uma ainda deve ser um rascunho: uma vez publicada, cancelada ou descartada, deixe esse ID de fora para iniciar um novo.
CorpoLink para esta seção#
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
products | array | sim | 1 a 100 produtos. SKUs devem ser únicos dentro da chamada. |
priceChangeId | string | não | Um rascunho da lista listPrice de uma chamada anterior. Preços alterados para essa lista são adicionados a ela. 404 se não existir, 400 se não for mais um rascunho. |
drafts | array | não | Até 30 entradas { list, priceChangeId } para que outros listas continuem seus próprios rascunhos. |
products[].sku | string | sim | Até 64 caracteres. |
products[].name | string | sim | Até 200 caracteres. |
products[].listPrice | inteiro ou nulo | sim | Unidades menores, de 0 a 1.000.000.000. null é preço sob consulta: um novo produto não tem preço, um existente mantém o seu próprio. |
products[].priceList | string ou nulo | não | Nome de uma lista de preços existente para listPrice. Omita ou null é Standard. Um nome desconhecido é rejeitado. |
products[].listPrices | array | não | Outras listas, como { list, price }. price são unidades menores, ou null para deixar essa lista inalterada. Um nome desconhecido é rejeitado. |
products[].unitLabel | string | sim | Até 60 caracteres, por exemplo, “Cada”. |
products[].brand | string | não | Nome da marca, até 120 caracteres. Limpo se omitido. |
products[].category | string | não | Nome da categoria, até 120 caracteres. Limpo se omitido. |
products[].manufacturerRef | string | não | Até 120 caracteres. Limpo se omitido. |
products[].description | string | não | Até 4.000 caracteres. Limpo se omitido. |
products[].availability | string | não | Um dos valores de disponibilidade. Mantido se omitido; novos produtos começam como not_tracked. |
products[].stockQty | inteiro ou nulo | não | Unidades em estoque, de -1.000.000 a 1.000.000.000. Define availability (veja o objeto do produto); um status que você envia junto é ignorado, exceto made_to_order. Mantido se omitido, a menos que você envie um availability sem ele: então a contagem é limpa e esse status é usado. null para parar de contar; o availability enviado na mesma linha aplica-se, ou o status atual se não houver nenhum. |
products[].lowStockAt | inteiro ou nulo | não | Nível de estoque baixo para esse produto, de 0. null usa o nível da workspace (Configurações, 5 para começar). Mantido se omitido. |
products[].leadTimeNote | string | não | Até 200 caracteres. Mantido se omitido. |
products[].dealText | string | não | Até 200 caracteres, mostrado ao lado do preço. Mantido se omitido. |
products[].details | objeto | não | Até 30 colunas extras: nomes até 60 caracteres, valores até 500. Substitui todos os detalhes quando enviado; mantido se omitido. |
products[].imageUrl | string | não | Uma URL de imagem https. Copiada para o TradeCatalog em segundo plano quando muda. Mantido se omitido. |
products[].onlyFor | array | não | Até 200 códigos de conta ou e-mails de contato. Torna o produto visível apenas para esses clientes, substituindo qualquer lista anterior. Mantido se omitido. |
Envie todos os campos que você se importa
brand, category, manufacturerRef e description são escritos como enviados, então deixar um de fora os limpa. Envie o produto completo a cada vez, como uma linha de planilha.
Esses não podem ser alterados por meio da API ainda: tornar um produto inativo, minOrderQty, remover uma imagem, limpar uma observação de tempo de entrega e tornar um produto exclusivo do cliente visível para todos novamente. Faça essas alterações no aplicativo.
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": []
}
}
| Campo | Descrição |
|---|---|
created | Novos produtos. |
updated | Produtos existentes correspondentes pelo SKU. |
priceChanges | Quantos preços entraram em um rascunho, em cada lista da chamada. |
priceChangeId | O rascunho para a lista listPrice, ou null se essa lista não tiver alterações. |
priceChangesByList | Um { list, priceChangeId } para cada lista que tiver uma alteração de preço nesta chamada. |
unknownCustomers | Valores em onlyFor que não corresponderam a nenhum cliente (até 50). Esses clientes não tiveram acesso. |
As alterações aparecem no log de atividade pelo nome da chave, e as atualizações de pesquisa ocorrem imediatamente.
Marcas e categoriasLink para esta seção#
GET/api/v1/brands
GET/api/v1/categories
Ambos retornam todas as linhas, classificadas pelo nome, sem paginação. Use os ids com os filtros brand e category em 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" }
]
}
Para criar uma marca ou categoria, dê um nome a ela em um produto em PUT /products.