API de parceiros: enviar pedidos e receber callbacks

Envio de pedidos (HMAC inbound hex), callbacks order.created e order.status_changed (HMAC outbound sha256=), endpoints de reconciliação, dedupe por X-N1-Delivery-Id, retry e circuit breaker auto-recovery.

Neste guia você vai…

  1. Montar a URL base e o endpoint POST /api/webhooks/partner/orders
  2. Assinar requisições inbound (parceiro → N1) em hex sem prefixo
  3. Validar callbacks outbound (N1 → parceiro) com sha256= no header
  4. Interpretar códigos de resposta e o ID PARTNER-{identificador}-{external_order_id}

URLs base

Todas as rotas usam o mesmo host da sua instância N1 (onde o painel está hospedado). Exemplos:

  • https://SEU-DOMINIO-N1.com/api/webhooks/partner/orders
  • https://SEU-DOMINIO-N1.com/api/webhooks/partner/docs
  • https://SEU-DOMINIO-N1.com/api/webhooks/partner/health

Substitua SEU-DOMINIO-N1.com pelo domínio real.

Inbound — enviar pedidos (POST /api/webhooks/partner/orders)

Headers obrigatórios

  • Content-Type: application/json
  • X-API-Key: chave no formato pk_live_ ou pk_test_ (a mesma exibida ao criar a API Key)
  • X-Webhook-Timestamp: Unix em segundos (inteiro)
  • X-Webhook-Signature: assinatura HMAC-SHA256 em hex ( sem prefixo sha256= )

Como calcular a assinatura (inbound)

  1. String assinada: timestamp + "." + corpo JSON bruto — o ponto é literal; o corpo deve ser exatamente os bytes enviados no body (mesma ordem de chaves, espaços e quebras de linha que forem enviados)
  2. HMAC-SHA256(string_assinada, webhook_secret) → saída em hexadecimal
  3. Envie esse hex em X-Webhook-Signature
assinatura = HMAC_SHA256_hex( timestamp + "." + rawBody, webhook_secret )

Janela de tempo

O X-Webhook-Timestamp deve estar a no máximo ~5 minutos do relógio do servidor (anti-replay). Timestamps fora da janela geram erro de assinatura/timestamp.

Respostas e erros

  • 201: pedido criado com sucesso (corpo inclui order_id)
  • 400: payload inválido (schema Zod) — corrija campos indicados em details
  • 401: API Key inválida/inativa ou assinatura HMAC inválida ou timestamp ausente/inválido — confira secret, string assinada e X-Webhook-Timestamp
  • 403: IP não permitido — quando whitelist de IP está configurada para essa chave (ajuste via administrador/API/suporte; não há tela disso no painel de API Keys)
  • 409: pedido duplicado — mesmo external_order_id para o mesmo identificador de parceiro
  • 429: rate limit — aguarde e tente de novo (há cabeçalho retry_after em segundos na resposta)

ID do pedido na N1

O ID interno gerado é:

PARTNER-{partnerIdentifier}-{external_order_id}

Use o mesmo external_order_id que você enviou no JSON para correlacionar com o sistema de origem.

Outbound — callbacks (N1 → seu endpoint)

Quando um pedido é criado ou muda de status, a N1 pode POST no seu callbackUrl (se configurado). A documentação completa com exemplos de validação está em GET /api/webhooks/partner/docs e no prompt de integração (botão no painel de API Keys).

Eventos

  • order.created: disparado imediatamente após criação bem-sucedida (útil como registro auditável além da resposta HTTP 201). Requer "created" em callback_events da API key.
  • order.status_changed: disparado em qualquer mudança de status da ordem, de qualquer fonte (ops interno, transportadora, 17TRACK, syncs).

O header X-N1-Event indica qual evento foi entregue.

Headers + assinatura

  • X-N1-Signature: sha256= + hex (diferente do inbound, que é só hex)
  • X-N1-Timestamp: Unix em segundos. Sua validação deve rejeitar fora da janela de 5 min.
  • X-N1-Event: order.created ou order.status_changed
  • X-N1-Delivery-Id: UUID único — seu código DEVE deduplicar por este valor (TTL ≥ 30 dias). O mesmo delivery pode chegar mais de uma vez (retries, replay manual).
  • Payload assinado: timestamp + "." + rawBody.

Retries, dead-letter e circuit breaker

  • Seu endpoint deve responder 2xx. Qualquer outro status (ou erro de rede) dispara retry: 3 tentativas com backoff 1min → 5min → dead-letter.
  • Circuit breaker (auto-recovery): após 10 falhas consecutivas, a N1 para de enviar por 30 min. Se ainda falhar ao reabrir, dobra: 60 min → 120 min → … cap em 24 h. Qualquer resposta 2xx reseta. Não exige ação manual (o botão de reativação no painel é apenas override).

Reconciliação (auto-recovery do parceiro)

Se seu endpoint ficou fora do ar ou você perdeu callbacks, 3 endpoints GET/POST deixam você se recuperar sem pedir ajuda manual. Exigem as mesmas 6 camadas de segurança do POST de criação; para GET, a string assinada é timestamp + "." + caminho-da-URL-com-query-string.

  • GET /api/webhooks/partner/orders/:external_order_id — estado atual de um pedido.
  • GET /api/webhooks/partner/orders?updated_since=ISO&limit=100&offset=0 — lista pedidos alterados após o timestamp (paginado).
  • POST /api/webhooks/partner/orders/:external_order_id/replay-callbacks — reenfileira os últimos N callbacks desse pedido (body: { "limit": 5 }, default 5, máx 20).

Exemplos completos em /api/webhooks/partner/docs e no prompt LLM do painel.

Saúde do serviço

GET /api/webhooks/partner/health — resposta pública { "status": "ok", ... } para monitoramento. Não exige autenticação.

Limitações e painel

Rate limit e whitelist de IP existem na API; se não aparecem no seu painel, trate ajuste via administrador ou suporte. Não assuma botões que não existem na interface.

Artigo relacionado

Configuração no painel (criar chave, secret, callback): API Keys de parceiros — painel.