Logística
Depois que o pedido tem documento fiscal, falta uma etiqueta pra sair da loja. Este guia cobre o modelo de shipments do pedido e a geração/download da etiqueta, que é uma operação assíncrona: você dispara, faz polling, baixa o PDF quando fica pronto.
O modelo mental
Um pedido pode ter um ou mais shipments. Cada shipment representa um pacote físico que sai da loja e tem um destino, transportador e (quando aplicável) código de rastreio. Para a maioria dos pedidos é 1 shipment, mas pode ter mais quando o mesmo pedido combina retirada parcial e envio parcial. Itens de origens (filiais/depósitos) diferentes não caem no mesmo pedido: cada origem gera seu próprio order_number sob o mesmo checkout_group_id.
Cada shipment tem zero, uma ou mais etiquetas (labels). A etiqueta é o arquivo que vai colado na caixa. Nem sempre é PDF: a4 e zebra_pdf são PDF, thermal é HTML e zebra é texto ZPL .txt. Pode ter mais de uma quando o transportador exige formatos diferentes (ex: A4 + impressão térmica) ou para shipments com múltiplos volumes.
Você como seller dispara a geração (fila um job em background), faz polling até as etiquetas ficarem prontas, e baixa cada uma via URL S3 assinada.
GET /orders/{id}/shipments devolve { "shipments": [ … ] }. Cada shipment:
{
"id": "01K8SHIP000TRACK01AAAAAAAA",
"type": "sales_order", // tipo: sales_order | return | transfer | pickup
"status": "ready_to_ship", // ← status do shipment (valores abaixo)
"tracking_code": "BR123…BR", // rastreio fica aqui, não na etiqueta
"carrier": {…}, // transportadora (id, name)
"labels": [{…}], // etiquetas deste shipment
"labels_ready": 1, // quantas já prontas
"labels_total": 1 // total esperado
}Os valores de status do shipment: pending, processing, ready_to_ship, in_transit, delivered, cancelled, return_in_progress, returned, awaiting_return, failed, error.
E cada label dentro de labels:
{
"id": "lbl_xyz",
"format": "a4", // formato: a4 | zebra | thermal (+ format_label em pt-BR)
"status": "completed", // ← pending | processing | completed | error
"is_ready": true, // já pode baixar? (pronto = completed)
"completed_at": "2026-04-26T16:02:00-03:00"
}Fluxo completo
1. Disparar geração
POST/api/v1/sellers/orders/{id}/shipment-labels/generate
Sem body. Enfileira um job para cada shipment do pedido. Resposta 202:
{
"success": true,
"data": {
"queued_shipments": [4421, 4422],
"total": 2
}
}queued_shipments lista os IDs efetivamente enfileirados. Pode ser menor que o número total de shipments do pedido quando algum tem label_generation_blocked=true (ver "Cuidados" abaixo).
Chamar de novo regenera. Se a primeira geração falhou ou se você corrigiu algo no shipment e quer outra rodada, basta chamar
/generatede novo: as etiquetas anteriores são descartadas e novos jobs são disparados.
2. Polling
GET/api/v1/sellers/orders/{id}/shipments
Consulta a lista de shipments com etiquetas embutidas. O que você procura em cada shipment é labels_ready === labels_total:
{
"data": {
"shipments": [
{
"id": "01K8SHIP000TRACK01AAAAAAAA",
"type": "sales_order",
"status": "ready_to_ship",
"tracking_code": "BR123456789BR",
"carrier": { "id": "01K8CARRIER000CORREIOS", "name": "Correios" },
"labels": [
{
"id": "lbl_xyz",
"format": "a4",
"format_label": "A4 (PDF)",
"status": "completed",
"is_ready": true,
"completed_at": "2026-04-26T16:02:00-03:00"
}
],
"labels_ready": 1,
"labels_total": 1
}
]
}
}Cadência recomendada: primeiros 15 segundos a cada 2s, depois a cada 5s, com timeout em 2 minutos. A geração típica leva 5–20 segundos por shipment dependendo do transportador.
3. Baixar a etiqueta
Quando is_ready=true, baixe via URL S3:
GET/api/seller/logistics/shipments/{id}/labels/{labelId}/download
{id} é o shipment.id, que é o ULID publicado pela API. {labelId} é o label.id.
{
"success": true,
"data": {
"label_id": "lbl_xyz",
"format": "a4",
"url": "https://s3.amazonaws.com/.../label_4421.pdf?X-Amz-Signature=...",
"expires_in": "15 minutos"
}
}A url é S3 assinada, válida por 15 minutos. Não armazene a URL; chame a rota de novo se precisar de outra cópia.
Se a etiqueta ainda não estiver pronta no momento do download, retorna 422 UNPROCESSABLE_ENTITY com Status: Em processamento. Volte para o polling antes de tentar de novo.
Rota alternativa (só labels)
Quando você já tem o shipment.id em mãos e só quer a lista de etiquetas (sem trazer o resto do shipment):
GET/api/seller/logistics/shipments/{id}/labels
É a mesma informação que vem dentro do shipment em /orders/{id}/shipments, mas servida isoladamente. Útil quando você está numa tela "detalhe do shipment" e não quer recarregar todos os shipments do pedido.
A resposta traz também o shipment_id e a lista formats_pending[] (formatos ainda em processamento), e cada label vem com source/source_label (de onde a etiqueta veio) e status_label em pt-BR: bom para exibir direto na tela.
Trabalhando pelo shipment
Além das rotas ancoradas no pedido, existe uma família ancorada no envio. Elas são úteis quando a sua tela é a expedição, não o pedido:
- Listar dá a fila de expedição da loja inteira (paginada), com transportadora, motorista e origem/destino. Os itens do pacote não vêm aqui: para eles, use o detalhe, que acrescenta
items[]. - Ajustar volumes redefine quantos pacotes o envio tem, antes do despacho. Recria os volumes do shipment, então rode antes de gerar etiqueta.
- Comprar frete efetiva a contratação junto à transportadora integrada, gerando etiqueta e rastreio pelo provedor.
- Confirmar entrega só vale quando a modalidade de logística permite confirmação manual (
allows_manual_confirmation=true) — é o mesmo critério explicado em Entrega.
Os campos e respostas de cada uma estão na seção Envios da referência.
Quando gerar (e quando não)
Antes de gerar, o documento fiscal precisa existir (NF-e registrada ou Declaração emitida). O motivo é prático: nenhum transportador aceita despachar uma encomenda sem nota acompanhando. A API não vai te impedir de gerar a etiqueta antes do fiscal (não é um erro técnico), mas o shipment vai ficar travado na hora do despacho. Por isso a ordem importa: resolva o fiscal primeiro e a etiqueta depois.
Ordem recomendada no fluxo padrão:
paid → preparing → [emite fiscal] → /shipment-labels/generate → ready_to_ship → shippedGere as etiquetas em preparing (depois do fiscal), imprima, cole na caixa, marque ready_to_ship quando o pacote estiver na transportadora.
Cuidados
Shipment com label_generation_blocked=true é pulado. Esse flag fica em true quando o sistema sabe que a etiqueta tem um problema impossível de resolver automaticamente (ex.: dados de endereço inválidos, conta com o transportador suspensa, peso fora do contrato). Você vai ver o shipment em queued_shipmentsvazio ou com total menor que o número real de shipments. Resolva o problema no shipment via operação antes de tentar gerar de novo.
Chamar /generate várias vezes regenera tudo. Não é incremental: uma chamada apaga as etiquetas anteriores e dispara jobs novos para todos os shipments não bloqueados. Use com consciência: se 1 de 3 shipments deu errado, chamar /generate vai regerar os outros 2 também.
A URL S3 expira em 15 minutos. Se você está montando uma tela de impressão em massa, gere as URLs sob demanda (no momento em que o usuário clica em "Imprimir"), não antes.
Tracking code aparece no shipment, não na label. Para ver o tracking_code, leia shipments[].tracking_code em /orders/{id}/shipments ou use GET /orders/{id}/tracking para a versão consolidada por pedido.
Retirada na loja é um método de entrega e, como todo método de entrega, também gera shipment.pickup é um "transporte" criado para a retirada no balcão: o pedido delivery_method=pickup gera um shipment com type=pickup (is_pickup=true), só que sem transportador nem rastreio, porque quem "transporta" é o próprio cliente. Esse shipment existe para produzir a etiqueta de identificação da retirada (template pickup-default): a que você cola no pacote separado no balcão. Ou seja, /generate funciona normalmente e retorna 202. O 404 "Nenhum shipment encontrado para este pedido." só acontece num pedido que, por algum erro, ficou sem nenhum shipment; não é o comportamento esperado de uma retirada.

