Preços
Todo produto tem uma tabela de preços por trás, mesmo quando é só uma linha. Dois modelos cobrem os dois jeitos de vender na plataforma: preço único (default), para quem vende no varejo, e preço progressivo por quantidade (wholesale, até 5 faixas), para quem também atende atacado e quer que o preço caia conforme a quantidade sobe.
Conceitos
price_type vive no produto e dita o comportamento da tabela:
price_type | Faixas permitidas | min_quantity |
|---|---|---|
default | Exatamente 1 | Sempre 1 |
wholesale | 1 a 5 progressivas | 1, depois valores crescentes |
O teto de 5 faixas vale para qualquer produto: a sexta faixa é recusada com 400.
Faixa é cada linha da tabela: par (min_quantity, price). A faixa que vale numa venda é a de maior min_quantity cujo valor é ≤ quantidade comprada.
A chave de cada faixa é o min_quantity. É por isso que PUT e DELETE recebem ele no path.
Quer voltar de
wholesaleparadefault? Só depois de deixar uma faixa só. Como odefaulté, por definição, uma tabela de uma linha, a plataforma não tem como adivinhar qual das suas faixas de atacado deve sobreviver: a decisão fica com você. Apague as faixas extras primeiro e aí a troca é liberada.
GET /products/{id}/prices devolve sempre um array de faixas: o que muda é o conteúdo conforme o price_type.
Padrão (default): exatamente 1 faixa.
[
{
"min_quantity": 1, // sempre 1 no default
"value": 89.9, // preço unitário único
"discount_percent": null // não se aplica
}
]Atacado (wholesale): 1 a 5 faixas progressivas.
[
{
"min_quantity": 1, // faixa base: preço da UMA unidade
"value": 50.0,
"discount_percent": null // no atacado automático a base fica 0; o % vai nas faixas seguintes
},
{
"min_quantity": 10, // faixa de atacado: a partir de 10 un
"value": 45.0, // preço unitário menor
"discount_percent": null
}
]No produto (
GET /api/productseGET /api/products/{id}), owholesalenão devolve umpriceúnico: a resposta trazmin_priceemax_price(o menor e o maior valor entre estas faixas).
Escala do preço (casas decimais)
O campo price das faixas (POST /api/products/{id}/prices e PUT /api/products/{id}/prices/{min_quantity}) aceita no máximo price_scale casas decimais:
advanced_pricing do produto | price_scale | Casas aceitas no price |
|---|---|---|
false (padrão) | 2 | 2 |
true | 3 | 3 |
Enviar 3 casas decimais em um SKU sem advanced_pricing retorna 422. O price_scale vem no objeto do produto (somente leitura): consulte-o antes de formatar e enviar o preço.
A precisão de 3 casas vale só para o preço unitário. O subtotal da linha e tudo que vem depois dele (totais do pedido, frete, comissão, split e pagamento) são sempre calculados com 2 casas, arredondados para cima. O motivo é prático: o gateway de pagamento não representa meio centavo.
Exemplo: unitário 0.375 (3 casas, produto com advanced_pricing) × 3 unidades = 1.125, cobrado como 1.13.
Preço padrão (default)
Produto vendido por valor unitário. Uma única faixa, sempre com min_quantity = 1.
Criar
{
"min_quantity": 1,
"price": 89.90
}Atualizar
PUT/api/products/{id}/prices/1
{
"price": 79.90
}Preço de atacado (wholesale)
Tabela progressiva por volume, até 5 faixas. Cada faixa tem o preço unitário vendido a partir daquela quantidade.
Recomendado: precifique por desconto (
%), não por valor fixo. Ligando oauto_wholesale_pricing, você informa só odiscount_percentde cada faixa e deixa o preço ser derivado do preço base. A gestão fica automática: você reajusta o preço base num lugar só e todas as faixas se recalculam sozinhas, sem reabrir faixa por faixa e sem risco de a tabela ficar inconsistente. Os dois modos estão documentados abaixo, mas comece pelo Atacado automático.
Exemplo de tabela montada:
| Faixa | min_quantity | price (unitário) | Quando vale |
|---|---|---|---|
| 1 | 1 | R$ 50,00 | 1 a 9 unidades |
| 2 | 10 | R$ 45,00 | 10 a 49 unidades |
| 3 | 50 | R$ 40,00 | 50 unidades ou mais |
A faixa base (min_quantity = 1) é sempre o preço unitário. As faixas de atacado são as de min_quantity ≥ 2.
Adicionar uma faixa (modo manual)
No modo manual você informa o price de cada faixa diretamente e fica responsável por reajustar faixa a faixa quando o preço mudar. (Para uma gestão mais simples, prefira o Atacado automático, a abordagem recomendada, em que você precifica por desconto.)
Faixa base (min_quantity = 1):
{
"min_quantity": 1,
"price": 50.00
}Faixa de atacado:
{
"min_quantity": 10,
"price": 45.00
}Reajustar uma faixa existente
PUT/api/products/{id}/prices/10
O corpo aceita o price e/ou o discount_percent. O merge parcial vale só para o discount_percent. O price não: se você não mandar, ele é zerado (no modo manual e na faixa base). Sempre reenvie o price no PUT.
{
"price": 42.50
}Remover uma faixa
DELETE/api/products/{id}/prices/10
A faixa base (min_quantity = 1) é protegida: tentar apagá-la devolve 400 com "Preço mínimo não pode ser removido". Todo produto sempre tem preço unitário.
O min_quantity de uma faixa também não muda no PUT — ele é a chave. Para mover uma faixa de 10 para 12, apague a de 10 e crie a de 12.
O que pode dar errado
| Erro | Quando acontece | Como tratar |
|---|---|---|
400 "Preço máximo atingido." | Você já tem 5 faixas nesse produto. | Remova uma faixa antes de criar outra. |
400 "Preço mínimo não pode ser removido." | DELETE na faixa min_quantity = 1. | A faixa base não sai; para trocar o valor, use o PUT. |
409 DUPLICATED | POST com um min_quantity que já existe. | Use o PUT daquela faixa em vez do POST. |
422 "Quantidade de preço inválida." | Faixa com min_quantity >= 2 num produto default. | Troque o price_type do produto para wholesale primeiro. |
422 "Defina o preço unitário base antes de criar faixas de atacado automáticas." | Atacado automático sem a faixa base cadastrada. | Crie a faixa min_quantity = 1 antes. |
422 desconto não progressivo | No atacado automático, a faixa maior tem desconto menor ou igual ao da faixa anterior. | Garanta descontos crescentes conforme a quantidade sobe. |
422 casas decimais | price com mais casas que o price_scale do SKU. | Ligue o advanced_pricing ou arredonde para 2 casas. |
422 SUBSTORE_CATALOG_READ_ONLY | A loja opera em modo espelho. | Preço é gerenciado pela matriz. |
Atacado automático
É a abordagem recomendada para o atacado: o preço passa a ser gerido num ponto só, o que mantém a tabela sempre coerente.
O produto tem um interruptor auto_wholesale_pricing (definido no próprio produto, junto do price_type). Quando ligado, você para de informar o price das faixas de atacado e passa a informar só o desconto (discount_percent). O preço de cada faixa é derivado do preço unitário base menos o desconto.
O discount_percent é sempre relativo ao preço base. O que fica salvo na faixa é o desconto, não um valor fixo: por isso, se você mudar o preço base, todas as faixas de atacado são recalculadas aplicando de novo o desconto de cada uma. Você ajusta o preço num lugar só.
Exemplo: preço base R$ 50,00, faixa de 50 un com discount_percent: 20 → preço da faixa = R$ 40,00. Se depois o base virar R$ 60,00, a mesma faixa passa sozinha para R$ 48,00.
Regras desse modo:
- O preço base (
min_quantity = 1) precisa existir antes de criar faixas de atacado: é dele que sai o cálculo. Sem ele, a API responde422. - O
discount_percentvai de0a menos de100. - Os descontos precisam ser progressivos: faixa de quantidade maior exige desconto maior que a anterior (o preço sempre cai conforme a quantidade sobe). Caso contrário,
422.
Faixa de atacado por desconto (em vez de price):
{
"min_quantity": 50,
"discount_percent": 20
}Comparando os dois modos para a mesma faixa: no manual você manda
"price": 40.00; no automático você manda"discount_percent": 20e a API calcula o preço a partir do base. No modo manual odiscount_percenté ignorado.
Listar a tabela
{
"success": true,
"message_code": "SUCCESS",
"data": [
{
"value": 50.00,
"min_quantity": 1,
"discount_percent": null
},
{
"value": 45.00,
"min_quantity": 10,
"discount_percent": null
}
]
}Cada faixa traz o valor (value), o min_quantity e o discount_percent (preenchido no atacado automático). A lista já vem ordenada por min_quantity ascendente, pronta pra renderizar na tela do comprador.

