Nesta página
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).
| Modo | Quem inicia | Como funciona | Quando usar |
|---|---|---|---|
| 1. Webhook de saída | Nouzz Hub | O 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 consulta | Logística | Você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. |
- 1OperadorAperta "Enviar para logística" no pedido
- 2Hub → LogísticaModo 1: o Hub envia order.ready_to_ship
- 3Logística → HubModo 2: vocês buscam GET /orders
- 4Logística → HubPOST /ack com o ID do pedido de vocês
- 5Logística → HubPOST /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.
| Item | Valor |
|---|---|
| URL base (produção) | https://nouzzhub.com.br/api/v1 |
| URL base (homologação) | https://nouzzhub.com.br/api/v1/sandbox |
| Header | Authorization: Bearer nzh_live_xxxxxxxxxxxxxxxx |
| Chave de teste | Começa com nzh_test_, só funciona na homologação |
| Formato | JSON em UTF-8, Content-Type: application/json |
| Datas | ISO 8601 com fuso, ex.: 2026-09-23T14:05:00-03:00 |
| Valores em dinheiro | Reais 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.
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.
| Campo | Tipo | Descrição |
|---|---|---|
id | string | ID do pedido no Hub. Use este nas chamadas de retorno. |
code | string | Código legível do pedido, ex.: NZH-8F2K1A. Pode ir na etiqueta. |
status | string | ready_to_ship (liberado), accepted (vocês aceitaram) ou canceled. |
created_at | datetime | Quando o pedido nasceu no Hub. |
released_at | datetime | Quando o operador liberou para a logística. |
payment_method | string | Sempre afterpay (o cliente paga depois de receber). |
amount | number | Valor total do pedido em reais. |
customer.name | string | Nome completo do destinatário. |
customer.document | string | CPF só com números (11 dígitos). |
customer.email | string | E-mail. Pode vir vazio. |
customer.phone | string | Celular com DDI e DDD, só números, ex.: 5511987654321. |
shipping_address.zip_code | string | CEP só com números (8 dígitos). |
shipping_address.street | string | Logradouro. |
shipping_address.number | string | Número. Pode ser S/N. |
shipping_address.complement | string | Complemento. Pode vir vazio. |
shipping_address.neighborhood | string | Bairro. |
shipping_address.city | string | Cidade. |
shipping_address.state | string | UF com 2 letras. |
items[].sku | string | SKU do kit, combinado entre nós na homologação. |
items[].partner_product_id | string | ID do produto no sistema de vocês, quando já mapeado. |
items[].name | string | Nome do produto e do kit, ex.: Revita Derme 3 frascos. |
items[].units | integer | Quantidade de unidades físicas no pacote. |
items[].quantity | integer | Quantidade do kit (normalmente 1). |
items[].unit_price | number | Preço do kit em reais. |
seller.name | string | Nome do produtor ou afiliado que vendeu. |
notes | string | Observações para a entrega. Pode vir vazio. |
{
"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
| Evento | Quando acontece |
|---|---|
order.ready_to_ship | Pedido liberado para envio. Criem o pedido de vocês a partir dele. |
order.updated | Endereço ou telefone corrigido antes da postagem. |
order.canceled | Pedido cancelado antes da postagem. Não despachem. |
Corpo da chamada
{
"event": "order.ready_to_ship",
"event_id": "evt_3f2a9c1e5b7d",
"sent_at": "2026-09-23T14:05:02-03:00",
"data": { "...": "objeto Pedido completo" }
}Headers enviados
| Header | Conteúdo |
|---|---|
Content-Type | application/json |
X-Nouzz-Event | Nome do evento |
X-Nouzz-Event-Id | ID único do evento (use para não processar duas vezes) |
X-Nouzz-Timestamp | Horário do envio em segundos (Unix) |
X-Nouzz-Signature | sha256= + HMAC-SHA256 do texto timestamp.corpo com o segredo whsec_... |
Conferindo a assinatura (Node.js)
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:
{ "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:
{ "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étodo | Endpoint | Para que serve |
|---|---|---|
| GET | /orders | Lista os pedidos da logística, com filtros |
| GET | /orders/{id} | Busca um pedido pelo ID do Hub |
| POST | /orders/{id}/ack | Confirma que vocês receberam e criaram o pedido |
| POST | /orders/{id}/reject | Recusa o pedido com um motivo |
Listar pedidos
/orders?status=ready_to_ship&updated_since=2026-09-23T00:00:00-03:00&limit=50| Parâmetro | Obrigatório | Descrição |
|---|---|---|
status | Não | ready_to_ship (padrão), accepted ou canceled |
updated_since | Não | Só pedidos alterados depois dessa data |
limit | Não | De 1 a 100. Padrão 50 |
cursor | Não | Valor de next_cursor da página anterior |
{
"data": [ { "...": "objeto Pedido" } ],
"has_more": true,
"next_cursor": "eyJpZCI6Im9yZF85YzFlIn0"
}Confirmar recebimento
/orders/{id}/ack{ "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
/orders/{id}/reject{ "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.
/orders/{id}/status{
"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"
}| Campo | Obrigatório | Descrição |
|---|---|---|
status | Sim | Um dos status da tabela abaixo |
occurred_at | Sim | Quando aconteceu de verdade (não quando vocês avisaram) |
tracking_code | A partir de shipped | Código de rastreio |
carrier | Não | Transportadora, ex.: Correios, Jadlog, Loggi |
tracking_url | Não | Link de rastreio para mostrar ao cliente |
message | Não | Texto livre, aparece no histórico do pedido |
Status aceitos
| Status | Significado | Como aparece no Hub |
|---|---|---|
scheduled | Pedido criado e em separação | Agendado |
shipped | Postado, em trânsito | Enviado |
out_for_delivery | Saiu para entrega | Saiu pra entrega |
delivery_failed | Tentativa de entrega sem sucesso | Entrega falhou |
awaiting_pickup | Aguardando retirada na agência | Aguardando retirada |
delivered | Entregue ao cliente | Entregue |
returned | Devolvido ao remetente | Devolvido |
canceled | Cancelado antes da postagem | Cancelado |
Regras que o Hub aplica
- Status que andam para trás são ignorados (ex.:
shippeddepois dedelivered). O Hub responde200e registra no histórico. canceledsó vale antes da entrega. Depois dedeliveredo 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:
{ "error": { "code": "order_not_found", "message": "Pedido não encontrado" } }| HTTP | Código | Quando acontece |
|---|---|---|
| 400 | invalid_payload | JSON inválido ou campo obrigatório faltando |
| 401 | invalid_api_key | Chave ausente, errada ou revogada |
| 403 | forbidden | O pedido não foi enviado para essa logística |
| 404 | order_not_found | ID de pedido inexistente |
| 409 | order_already_accepted | /ack com um partner_order_id diferente do já registrado |
| 422 | invalid_status | Status fora da lista aceita |
| 429 | rate_limited | Passou do limite de chamadas |
| 500 | internal_error | Erro 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 headerRetry-After. - Em
/acke/statuspode mandar o headerIdempotency-Key(qualquer texto único). A mesma chave repetida em 24 h devolve a mesma resposta, sem duplicar nada. - Guardem o
iddo 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:
- 1Receber a chave
nzh_test_e o segredowhsec_de homologação - 2Combinar a tabela de SKUs dos kits com os IDs de produto de vocês
- 3Modo 1: receber um
order.ready_to_shipde teste e validar a assinatura - 4Modo 2: listar, buscar e dar
/acknum pedido de teste - 5Mandar a sequência
scheduled,shipped(com rastreio),out_for_deliveryedelivered - 6Testar um
/rejecte umcanceledantes da postagem - 7Trocar para a chave
nzh_live_e acompanhar juntos o primeiro pedido real