Frete e Cotação¶
A Gubee mantém um motor interno de cotação de frete que combina regras configuradas pelo seller (tabela de fretes próprios) com integrações diretas a transportadoras (Correios, Intelipost e outras). Esta página descreve como um parceiro pode cotar frete para um conjunto de SKUs destino um CEP.
Modelo de dados¶
| Entidade | Descrição |
|---|---|
| Carrier (Transportadora) | Empresa que faz a entrega física (Correios, Jadlog, Intelipost como agregador, etc) |
| Region (Região) | Faixa de CEPs atendida por um conjunto de transportadoras |
| Freight Value (Valor de Frete) | Combinação Carrier × Region × Faixa de peso que define preço e prazo |
| Freight Type | Categoria de serviço: STANDARD, EXPRESS, ECONOMIC, etc |
| Quote (Cotação) | Resultado de um cálculo de frete para 1+ SKUs destino um CEP |
A configuração de carriers/regions/values é feita via UI interna do admin
(Fretes > Transportadora, Fretes > Região, Fretes > Valores de Frete).
Esses endpoints estão em /bffweb/* e não são expostos na API de integração
pública — parceiros só consomem cotações via /integration/quotes.
Endpoint de cotação¶
A API pública de cotação é aberta (não requer JWT do seller):
{sellerId}: identificador do seller cuja tabela de frete será usada{postalCode}: CEP de destino (apenas dígitos, ex.:01310100)- Body: lista de
quotationItems(skuId + quantidade) - Response: lista de
shippingQuotescomcarrier,service,cost,deliveryTime(prazo em horas) edeadlineDays(prazo em dias úteis)
Por que esse endpoint é público (sem JWT)?¶
Cotação de frete acontece tipicamente no checkout de e-commerce, antes
do login do comprador. Exigir JWT do seller seria impraticável nesse
cenário. Por isso o sellerId é recebido como path variable — qualquer
comprador pode cotar frete para qualquer seller.
Não abuse da exceção
O sellerId no path é exclusivo deste endpoint. Todos os outros
endpoints /integration/* ignoram qualquer sellerId enviado no body
e usam o sellerId extraído do JWT. Veja
Autenticação.
Request¶
curl -X POST 'https://api.gubee.com.br/integration/quotes/SEU_SELLER_ID/01310100' \
-H 'Content-Type: application/json' \
-d '{
"quotationItems": [
{ "skuId": "ABCD-1234-EFGH-5678", "qty": 2 },
{ "skuId": "IJKL-9012-MNOP-3456", "qty": 1 }
]
}'
Response (200 OK)¶
{
"postalCode": 1310100,
"shippingQuotes": [
{
"valueFreightId": "vf-001",
"freightServiceId": "sedex",
"freightServiceName": "Sedex",
"freightType": "STANDARD",
"deliveryTime": 48,
"deadlineDays": 2,
"carrierId": "correios",
"carrierName": "Correios",
"weight": { "value": 2.5, "unit": "KILOGRAM" },
"shippingCost": 32.90,
"skuQty": { "skuId": "ABCD-1234-EFGH-5678", "qty": 2 }
},
{
"valueFreightId": "vf-002",
"freightServiceId": "pac",
"freightServiceName": "PAC",
"freightType": "ECONOMIC",
"deliveryTime": 96,
"deadlineDays": 5,
"carrierId": "correios",
"carrierName": "Correios",
"weight": { "value": 2.5, "unit": "KILOGRAM" },
"shippingCost": 22.50,
"skuQty": { "skuId": "ABCD-1234-EFGH-5678", "qty": 2 }
}
]
}
Campos da resposta¶
| Campo | Tipo | Descrição |
|---|---|---|
postalCode |
Long | CEP de destino (echo do path) |
shippingQuotes |
Set | Lista de opções de frete (uma por combinação carrier × serviço) |
shippingQuotes[].valueFreightId |
String | ID interno da regra de frete que produziu a cotação |
shippingQuotes[].freightServiceId |
String | ID do serviço na transportadora (ex.: sedex, pac, jadlog-package) |
shippingQuotes[].freightServiceName |
String | Nome amigável do serviço |
shippingQuotes[].freightType |
Enum | Tipo: STANDARD, EXPRESS, ECONOMIC, etc |
shippingQuotes[].deliveryTime |
Int | Prazo em horas (para o SKU descrito em skuQty) |
shippingQuotes[].deadlineDays |
Int | Prazo em dias úteis (echo amigável) |
shippingQuotes[].carrierId |
String | ID da transportadora (ex.: correios, intelipost) |
shippingQuotes[].carrierName |
String | Nome amigável da transportadora |
shippingQuotes[].weight |
Object | Peso considerado no cálculo (value + unit) |
shippingQuotes[].shippingCost |
BigDecimal | Custo do frete em BRL |
shippingQuotes[].skuQty |
Object | SKU ao qual esta cotação se refere (pode haver uma quote por SKU) |
Erros comuns¶
| HTTP | Causa |
|---|---|
404 |
skuId não encontrado para o seller, ou SKU sem dimensão/peso cadastrado |
400 |
postalCode inválido, qty <= 0, ou quotationItems vazio |
422 |
Região do CEP não atendida por nenhuma transportadora do seller |
Tipos de frete (FreightType)¶
| Valor | Significado |
|---|---|
STANDARD |
Padrão — equilíbrio custo vs prazo |
EXPRESS |
Entrega expressa (ex.: Sedex) |
ECONOMIC |
Mais barato, prazo mais longo (ex.: PAC) |
SAME_DAY |
Mesmo dia (apenas cidades selecionadas) |
NEXT_DAY |
Próximo dia |
PICKUP |
Retirada no CD (sem entrega física) |
A disponibilidade de cada tipo depende da configuração de carriers e regions do seller.
Integrações com transportadoras¶
A Gubee integra nativamente com as seguintes transportadoras:
| Integração | Categoria | Como configurar |
|---|---|---|
| Correios | Logística essencial | Admin > Fretes > Transportadora > adicionar Correios com contrato/serviços |
| Intelipost | Agregador multi-carrier | Admin > Fretes > Transportadora > adicionar Intelipost com API key |
Quando o seller usa Intelipost, a Gubee delega o cálculo de frete para o
motor da Intelipost, que retorna múltiplas opções de carriers reais (Jadlog,
Azul Cargo, Braspress, etc). Nesse caso, o campo carrierName na resposta
pode ser diferente de "Correios".
Quando o seller usa tabela própria (sem agregador), a cotação é calculada
internamente pela Gubee a partir das Freight Values configuradas.
Quando uma cotação falha silenciosamente¶
Às vezes a resposta vem com shippingQuotes vazio ([]) mesmo para um CEP
válido. Causas típicas:
- SKU sem dimensão: o cálculo de frete precisa de peso + dimensões.
Verifique
dimension.weight/height/width/lengthna variação (GET /integration/products/v2/bySkuId/{skuId}). - Região não atendida: o CEP destino não cai em nenhuma
Regionconfigurada pelo seller. Adicione a região no admin. - Faixa de peso sem valor: o SKU excede o peso máximo de todas as faixas configuradas para a region.
- Carrier inativa: a transportadora foi desativada no admin mas a region continua apontando pra ela.
Em todos os casos, a cotação não retorna erro explícito — apenas []. O
checkout do parceiro deve tratar isso como "frete indisponível" e sugerir
CEP alternativo ou contato com o seller.
Performance¶
- A cotação é síncrona (sem plataforma de streaming de eventos): chamou, recebeu a resposta na mesma requisição.
- Latência típica: 100-300ms para tabela própria; 500-2000ms para integração externa (Correios/Intelipost).
- Rate limit recomendado: máx 10 cotações/segundo por seller. Acima disso,
considere cachear resultados por
(skuId, qty, CEP)por 5 minutos.
Próximos passos¶
- Pedidos e Ciclo de Vida: o status
SHIPPEDusa a transportadora escolhida na cotação. - Etiquetas (Correios/Intelipost): geração de etiqueta de envio após faturamento.
- Integrações de Logística: lista completa de ERPs e transportadoras integradas.
Apêndice: Contrato de cotação externa (Gubee chama você)¶
Além da cotação interna (motor da Gubee), existe um cenário em que o seller quer usar seu próprio motor de frete (ERP, transportadora própria, etc). Nesse caso, a Gubee chama o endpoint do seller durante o checkout e usa a resposta para exibir opções de frete ao comprador.
Este é o fluxo reverso: ao invés de o parceiro chamar POST /integration/quotes,
o parceiro implementa um endpoint HTTP e a Gubee o chama como cliente.
Como ativar¶
Painel da Gubee > Fretes > Transportadora:
- Adicionar uma nova transportadora
- Marcar a flag "Utilizar integração"
- Selecionar a opção "Api"
- Informar a URL do seu endpoint no campo "Url para cotação"
- Adicionar pelo menos 1 tipo de serviço (Standard, Express, etc) à transportadora
- Em Fretes > Região, criar uma região (faixa de CEP) e associar essa transportadora — sempre que um checkout cair nessa região, a Gubee chama seu endpoint
Contrato do endpoint¶
Implemente um endpoint público (sem autenticação) com as características abaixo. A Gubee é o cliente; você é o servidor.
{postalCode}: CEP de destino, apenas dígitos (path parameter)- Tempo máximo aceito pela Gubee: 650ms — acima disso, a Gubee descarta a resposta e usa apenas cotações internas. Otimize agressivamente.
Payload de entrada (Gubee envia para você)¶
{
"orderTotalPrice": 1999.90,
"platform": "MERCADOLIVRE",
"quotationItems": [
{
"dimension": {
"depthInCm": 54.0,
"heightInCm": 23.0,
"weightInGr": 2500.0,
"widthInCm": 41.0
},
"price": 199.99,
"qty": 10,
"skuId": "28"
}
]
}
| Campo | Tipo | Descrição |
|---|---|---|
orderTotalPrice |
BigDecimal | Total do pedido (informado pelo marketplace OU soma de itens × preço cadastrado) |
platform |
String | Nome do marketplace (MERCADOLIVRE, AMAZON, B2W, SHOPEE, ALIEXPRESS, etc). Pode ser null — não conte com ele |
quotationItems[] |
Array | Lista de SKUs a cotar |
quotationItems[].dimension.depthInCm |
Double | Profundidade unitária em cm |
quotationItems[].dimension.heightInCm |
Double | Altura unitária em cm |
quotationItems[].dimension.weightInGr |
Double | Peso unitário em gramas |
quotationItems[].dimension.widthInCm |
Double | Largura unitária em cm |
quotationItems[].price |
BigDecimal | Preço unitário do SKU |
quotationItems[].qty |
Int | Quantidade no pedido |
quotationItems[].skuId |
String | Identificador interno da variação na Gubee |
Payload de resposta (você retorna para a Gubee)¶
{
"postalCode": 1310100,
"shippingQuotes": [
{
"carrierId": "5f43cb7085609a3239a38cfc",
"carrierName": "TRANSPORTADORA",
"deadlineDays": 8,
"deliveryTime": 8,
"freightServiceId": "fd8f7ae0-77f5-4cda-89ab-88dbb8ab0ed7",
"freightServiceName": "ECONOMICO",
"freightType": "ECONOMIC",
"shippingCost": 32.8125,
"skuQty": {
"crossDockingTime": 0,
"handlingTime": 0,
"qty": 2,
"skuId": "28",
"stockQty": 6
},
"valueFreightId": "62b3507361f0761d57391ed0",
"weight": {
"type": "GRAM",
"value": 5000.0
}
}
]
}
| Campo | Tipo | Descrição |
|---|---|---|
postalCode |
Long | Echo do CEP de destino |
shippingQuotes[] |
Array | Lista de opções de frete |
shippingQuotes[].carrierId |
String | ID interno da sua transportadora |
shippingQuotes[].carrierName |
String | Nome amigável |
shippingQuotes[].deadlineDays |
Int | Prazo em dias úteis |
shippingQuotes[].deliveryTime |
Int | Prazo em dias (echo) |
shippingQuotes[].freightServiceId |
String | ID do serviço na transportadora |
shippingQuotes[].freightServiceName |
String | Nome amigável |
shippingQuotes[].freightType |
Enum | Obrigatório: ECONOMIC, NORMAL ou EXPRESS |
shippingQuotes[].shippingCost |
BigDecimal | Custo em BRL |
shippingQuotes[].skuQty.crossDockingTime |
Int | Tempo de cross-docking em dias |
shippingQuotes[].skuQty.handlingTime |
Int | Tempo de manipulação em dias |
shippingQuotes[].skuQty.qty |
Int | Quantidade cotada (pode diferir da entrada se vocês vendem em pack múltiplo) |
shippingQuotes[].skuQty.skuId |
String | Echo do skuId |
shippingQuotes[].skuQty.stockQty |
Int | Estoque disponível (opcional — usado para UX no checkout) |
shippingQuotes[].valueFreightId |
String | ID interno da sua regra de frete |
shippingQuotes[].weight.type |
String | Unidade: GRAM, KILOGRAM |
shippingQuotes[].weight.value |
Double | Peso total considerado |
Validações importantes¶
freightTypeDEVE ser um destes:ECONOMIC,NORMAL,EXPRESS. Outros valores são rejeitados silenciosamente (a cotação some do checkout).- HTTP status 2xx com body JSON válido. Qualquer outro status (4xx, 5xx) descarta a cotação inteira.
- Latência ≤ 650ms. Use cache agressivo por
(skuId, qty, CEP). Se você precisa de mais tempo, não use este contrato — crie uma cotação assíncrona na sua ponta e use um webhook pra depois atualizar viaPUT /prices.
Exemplo de implementação (pseudocódigo)¶
# Flask / FastAPI / qualquer framework
@app.post("/freight/<int:postal_code>")
def quote_freight(postal_code: int):
body = request.json
items = body.get("quotationItems", [])
# Sua lógica: consulta tabela propria, chama transportadora, etc
quotes = []
for item in items:
# Exemplo simples: R$ 0.50 por grama + taxa fixa R$ 10
weight_kg = item["dimension"]["weightInGr"] / 1000
cost = (weight_kg * 0.50 * item["qty"]) + 10
quotes.append({
"carrierId": "my-carrier-001",
"carrierName": "Minha Transportadora",
"deadlineDays": 5,
"deliveryTime": 5,
"freightServiceId": "std",
"freightServiceName": "Padrão",
"freightType": "NORMAL",
"shippingCost": round(cost, 2),
"skuQty": {
"crossDockingTime": 1,
"handlingTime": 1,
"qty": item["qty"],
"skuId": item["skuId"],
"stockQty": 999
},
"valueFreightId": "rule-001",
"weight": {
"type": "GRAM",
"value": item["dimension"]["weightInGr"] * item["qty"]
}
})
return jsonify({
"postalCode": postal_code,
"shippingQuotes": quotes
})
Quando usar este contrato vs /integration/quotes¶
| Cenário | Use |
|---|---|
| Você tem tabela de frete interna na Gubee (Correios, Intelipost ou manual) | POST /integration/quotes (cotação interna) |
| Você quer usar seu ERP como motor de frete durante o checkout na Gubee | Este contrato (cotação externa) |
| Você só precisa de uma cotação para exibir no seu site/app, sem ser parte do checkout | POST /integration/quotes |
A diferença fundamental: /integration/quotes é o parceiro pedindo cotação
pra Gubee usar; este contrato é a Gubee pedindo cotação pro parceiro durante
o fluxo de compra real na Gubee.