Nouzz Hub· API v1
Nesta página
Integração de logística

API do Nouzz Hub para logísticas

Receba os pedidos do Hub no seu sistema com um clique do operador e devolva o status e o rastreio de cada pacote. Tudo em JSON, com autenticação por chave e webhooks assinados.

Visão geral

O Nouzz Hub é a plataforma onde nascem os pedidos de venda com pagamento na entrega (afterpay) de produtores e afiliados. Esta API liga o Hub à sua logística: o pedido sai do Hub para vocês, e o status e o rastreio voltam de vocês para o Hub.

Existem dois jeitos de receber os pedidos. Vocês escolhem um, ou usam os dois (o webhook como principal e a consulta como garantia).

ModoQuem iniciaComo funcionaQuando usar
1. Webhook de saídaNouzz HubO operador aperta "Enviar para logística" e o Hub faz um POST na URL de vocês com o pedido completo.Vocês têm um endpoint para receber pedidos. É o jeito mais rápido.
2. API de consultaLogísticaVocês consultam o Hub de tempos em tempos e buscam os pedidos liberados para envio.Vocês preferem buscar os pedidos em lote, no horário de vocês.
  1. 1
    Operador
    Aperta "Enviar para logística" no pedido
  2. 2
    Hub → Logística
    Modo 1: o Hub envia order.ready_to_ship
  3. 3
    Logística → Hub
    Modo 2: vocês buscam GET /orders
  4. 4
    Logística → Hub
    POST /ack com o ID do pedido de vocês
  5. 5
    Logística → Hub
    POST /status a cada mudança, até a entrega

O pedido só aparece para a logística depois que o operador libera o envio. Pedido em rascunho ou cancelado nunca é enviado.

Autenticação

Toda chamada à API do Hub leva uma chave de API no header Authorization. Cada logística parceira recebe a sua chave e só enxerga os pedidos que foram enviados para ela.

ItemValor
URL base (produção)https://nouzzhub.com.br/api/v1
URL base (homologação)https://nouzzhub.com.br/api/v1/sandbox
HeaderAuthorization: Bearer nzh_live_xxxxxxxxxxxxxxxx
Chave de testeComeça com nzh_test_, só funciona na homologação
FormatoJSON em UTF-8, Content-Type: application/json
DatasISO 8601 com fuso, ex.: 2026-09-23T14:05:00-03:00
Valores em dinheiroReais com duas casas decimais, ex.: 297.00

Para o Modo 1 (webhook), vocês nos passam também a URL que vai receber os pedidos e nós passamos um segredo de assinatura (whsec_...), usado para vocês confirmarem que a chamada veio do Hub.

A chave é gerada pelo produtor dentro do Hub, em Integrações, e pode ser revogada a qualquer momento. Nunca coloquem a chave em código de front-end.

bash
curl https://nouzzhub.com.br/api/v1/orders?status=ready_to_ship \
  -H "Authorization: Bearer nzh_live_xxxxxxxxxxxxxxxx"

O objeto Pedido

O pedido tem o mesmo formato no webhook e na API de consulta. Tudo que a logística precisa para despachar está nele: destinatário, endereço, itens e valor a cobrar.

CampoTipoDescrição
idstringID do pedido no Hub. Use este nas chamadas de retorno.
codestringCódigo legível do pedido, ex.: NZH-8F2K1A. Pode ir na etiqueta.
statusstringready_to_ship (liberado), accepted (vocês aceitaram) ou canceled.
created_atdatetimeQuando o pedido nasceu no Hub.
released_atdatetimeQuando o operador liberou para a logística.
payment_methodstringSempre afterpay (o cliente paga depois de receber).
amountnumberValor total do pedido em reais.
customer.namestringNome completo do destinatário.
customer.documentstringCPF só com números (11 dígitos).
customer.emailstringE-mail. Pode vir vazio.
customer.phonestringCelular com DDI e DDD, só números, ex.: 5511987654321.
shipping_address.zip_codestringCEP só com números (8 dígitos).
shipping_address.streetstringLogradouro.
shipping_address.numberstringNúmero. Pode ser S/N.
shipping_address.complementstringComplemento. Pode vir vazio.
shipping_address.neighborhoodstringBairro.
shipping_address.citystringCidade.
shipping_address.statestringUF com 2 letras.
items[].skustringSKU do kit, combinado entre nós na homologação.
items[].partner_product_idstringID do produto no sistema de vocês, quando já mapeado.
items[].namestringNome do produto e do kit, ex.: Revita Derme 3 frascos.
items[].unitsintegerQuantidade de unidades físicas no pacote.
items[].quantityintegerQuantidade do kit (normalmente 1).
items[].unit_pricenumberPreço do kit em reais.
seller.namestringNome do produtor ou afiliado que vendeu.
notesstringObservações para a entrega. Pode vir vazio.
json
{
  "id": "ord_9c1e5b7d4e8a",
  "code": "NZH-8F2K1A",
  "status": "ready_to_ship",
  "created_at": "2026-09-23T10:12:00-03:00",
  "released_at": "2026-09-23T14:05:00-03:00",
  "payment_method": "afterpay",
  "amount": 297.00,
  "customer": {
    "name": "Maria da Silva",
    "document": "12345678909",
    "email": "maria@email.com",
    "phone": "5511987654321"
  },
  "shipping_address": {
    "zip_code": "01310100",
    "street": "Avenida Paulista",
    "number": "1000",
    "complement": "Apto 52",
    "neighborhood": "Bela Vista",
    "city": "São Paulo",
    "state": "SP"
  },
  "items": [
    {
      "sku": "REVITA-3FR",
      "partner_product_id": "48213",
      "name": "Revita Derme 3 frascos",
      "units": 3,
      "quantity": 1,
      "unit_price": 297.00
    }
  ],
  "seller": { "name": "Loja Exemplo" },
  "notes": "Entregar após as 14h"
}

Modo 1: webhook de saída (o Hub envia para vocês)

Quando o operador aperta "Enviar para logística", o Hub faz um POST na URL cadastrada de vocês em até 5 segundos. Vocês só precisam de um endpoint que receba o JSON e responda.

Eventos enviados

EventoQuando acontece
order.ready_to_shipPedido liberado para envio. Criem o pedido de vocês a partir dele.
order.updatedEndereço ou telefone corrigido antes da postagem.
order.canceledPedido cancelado antes da postagem. Não despachem.

Corpo da chamada

json
{
  "event": "order.ready_to_ship",
  "event_id": "evt_3f2a9c1e5b7d",
  "sent_at": "2026-09-23T14:05:02-03:00",
  "data": { "...": "objeto Pedido completo" }
}

Headers enviados

HeaderConteúdo
Content-Typeapplication/json
X-Nouzz-EventNome do evento
X-Nouzz-Event-IdID único do evento (use para não processar duas vezes)
X-Nouzz-TimestampHorário do envio em segundos (Unix)
X-Nouzz-Signaturesha256= + HMAC-SHA256 do texto timestamp.corpo com o segredo whsec_...

Conferindo a assinatura (Node.js)

javascript
const crypto = require("crypto");

function assinaturaValida(req, corpoBruto, segredo) {
  const ts = req.headers["x-nouzz-timestamp"];
  const recebida = req.headers["x-nouzz-signature"];
  const esperada = "sha256=" + crypto
    .createHmac("sha256", segredo)
    .update(`${ts}.${corpoBruto}`)
    .digest("hex");
  const recente = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return recente && crypto.timingSafeEqual(Buffer.from(recebida), Buffer.from(esperada));
}

O que responder

Respondam 200 em até 10 segundos. Se já criaram o pedido de vocês, mandem o ID no corpo e o Hub já marca como aceito, sem precisar chamar o /ack:

json
{ "partner_order_id": "BL-558812", "tracking_code": null }

Se o pedido tiver algum problema (CEP fora da área, produto sem estoque), respondam 422 com o motivo. O Hub mostra essa mensagem para o operador corrigir:

json
{ "error": "CEP 69900000 fora da área de entrega" }

Retentativas

Qualquer resposta diferente de 2xx ou 422, ou sem resposta em 10 segundos, conta como falha. O Hub tenta de novo em 1 min, 5 min, 30 min, 2 h e 6 h. Depois disso o pedido volta para o operador como "envio falhou". Por causa das retentativas, o mesmo event_id pode chegar mais de uma vez: tratem como a mesma coisa.

Modo 2: API de consulta (vocês buscam no Hub)

Vocês buscam os pedidos liberados e confirmam cada um com o /ack. Pedido confirmado sai da fila e não volta mais na listagem de ready_to_ship. Sugerimos consultar a cada 5 minutos.

MétodoEndpointPara que serve
GET/ordersLista os pedidos da logística, com filtros
GET/orders/{id}Busca um pedido pelo ID do Hub
POST/orders/{id}/ackConfirma que vocês receberam e criaram o pedido
POST/orders/{id}/rejectRecusa o pedido com um motivo

Listar pedidos

GET/orders?status=ready_to_ship&updated_since=2026-09-23T00:00:00-03:00&limit=50
ParâmetroObrigatórioDescrição
statusNãoready_to_ship (padrão), accepted ou canceled
updated_sinceNãoSó pedidos alterados depois dessa data
limitNãoDe 1 a 100. Padrão 50
cursorNãoValor de next_cursor da página anterior
json
{
  "data": [ { "...": "objeto Pedido" } ],
  "has_more": true,
  "next_cursor": "eyJpZCI6Im9yZF85YzFlIn0"
}

Confirmar recebimento

POST/orders/{id}/ack
json
{ "partner_order_id": "BL-558812", "tracking_code": null }

Resposta 200 com o pedido atualizado para accepted. Chamar o /ack de novo com o mesmo partner_order_id não dá erro, só devolve o mesmo resultado.

Recusar pedido

POST/orders/{id}/reject
json
{ "reason": "CEP fora da área de entrega" }

O pedido volta para o operador no Hub com o motivo, para ele corrigir e liberar de novo.

Retorno da logística (status e rastreio)

A cada mudança no pacote, vocês chamam POST /orders/{id}/status. É isso que move o pedido no Hub e avisa o vendedor e o cliente. A cobrança do cliente fica com o Hub: a logística não recebe pagamento.

POST/orders/{id}/status
json
{
  "status": "shipped",
  "tracking_code": "AB123456789BR",
  "carrier": "Correios",
  "tracking_url": "https://rastreamento.correios.com.br/app/index.php?objeto=AB123456789BR",
  "occurred_at": "2026-09-24T09:30:00-03:00",
  "message": "Objeto postado"
}
CampoObrigatórioDescrição
statusSimUm dos status da tabela abaixo
occurred_atSimQuando aconteceu de verdade (não quando vocês avisaram)
tracking_codeA partir de shippedCódigo de rastreio
carrierNãoTransportadora, ex.: Correios, Jadlog, Loggi
tracking_urlNãoLink de rastreio para mostrar ao cliente
messageNãoTexto livre, aparece no histórico do pedido

Status aceitos

StatusSignificadoComo aparece no Hub
scheduledPedido criado e em separaçãoAgendado
shippedPostado, em trânsitoEnviado
out_for_deliverySaiu para entregaSaiu pra entrega
delivery_failedTentativa de entrega sem sucessoEntrega falhou
awaiting_pickupAguardando retirada na agênciaAguardando retirada
deliveredEntregue ao clienteEntregue
returnedDevolvido ao remetenteDevolvido
canceledCancelado antes da postagemCancelado

Regras que o Hub aplica

  • Status que andam para trás são ignorados (ex.: shipped depois de delivered). O Hub responde 200 e registra no histórico.
  • canceled só vale antes da entrega. Depois de delivered o produto já está com o cliente, e o Hub ignora o cancelamento.
  • Mandar o mesmo status duas vezes não dá erro.
  • Mudar só o código de rastreio: mandem o mesmo status com o código novo.

Erros e limites

Toda resposta de erro tem o mesmo formato, com um código fixo para o sistema de vocês tratar e uma mensagem em português:

json
{ "error": { "code": "order_not_found", "message": "Pedido não encontrado" } }
HTTPCódigoQuando acontece
400invalid_payloadJSON inválido ou campo obrigatório faltando
401invalid_api_keyChave ausente, errada ou revogada
403forbiddenO pedido não foi enviado para essa logística
404order_not_foundID de pedido inexistente
409order_already_accepted/ack com um partner_order_id diferente do já registrado
422invalid_statusStatus fora da lista aceita
429rate_limitedPassou do limite de chamadas
500internal_errorErro do nosso lado. Pode tentar de novo

Limites e boas práticas

  • 120 chamadas por minuto por chave. Ao receber 429, esperem o tempo do header Retry-After.
  • Em /ack e /status pode mandar o header Idempotency-Key (qualquer texto único). A mesma chave repetida em 24 h devolve a mesma resposta, sem duplicar nada.
  • Guardem o id do Hub junto com o pedido de vocês. É ele que liga os dois lados.
  • Campos novos podem aparecer no JSON sem aviso. Ignorem o que não conhecerem.

Homologação

O caminho até o primeiro pedido real, feito junto com a equipe do Hub:

  1. 1Receber a chave nzh_test_ e o segredo whsec_ de homologação
  2. 2Combinar a tabela de SKUs dos kits com os IDs de produto de vocês
  3. 3Modo 1: receber um order.ready_to_ship de teste e validar a assinatura
  4. 4Modo 2: listar, buscar e dar /ack num pedido de teste
  5. 5Mandar a sequência scheduled, shipped (com rastreio), out_for_delivery e delivered
  6. 6Testar um /reject e um canceled antes da postagem
  7. 7Trocar para a chave nzh_live_ e acompanhar juntos o primeiro pedido real