Nomba Webhooks

Construa um endpoint de webhook seguro para a Nomba que verifica a assinatura, desduplica entregas e reage corretamente a cada evento (payment_success, payment_failed, payment_reversal, payout_success, payout_failed, payout_refund).

O que é Nomba Webhooks?

Esta habilidade orienta você a criar um endpoint de webhook robusto e seguro para a Nomba, a plataforma de pagamentos africana. Ela explica por que a verificação adequada da assinatura HMAC é crucial – para garantir que apenas solicitações legítimas da Nomba sejam processadas – e por que você deve usar o SDK oficial da Nomba em vez de implementar sua própria lógica. A habilidade detalha um processo passo a passo: obter o corpo bruto da requisição, verificar a assinatura com o SDK, desduplicar eventos usando o campo `requestId` para lidar com repetições, responder rapidamente com 200 e processar ações pesadas (como e-mails ou atualizações de pedidos) em segundo plano. Ela também aborda as nuances de cada tipo de evento (`payment_success`, `payout_failed`, etc.), a importância de consultar novamente a API da Nomba para confirmar valores antes de realizar reembolsos ou armazenar tokens de cartão (já que a assinatura não cobre valores monetários), e as melhores práticas de proteção contra replay. A habilidade é compatível com os principais frameworks em Node.js, Python e PHP, e inclui exemplos de código, uma checklist de implantação e instruções de teste.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/NombaOSS/skills/tree/HEAD/skills/nomba-webhooks

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Webhooks da Nomba

Um webhook é como a Nomba informa ao seu servidor que o dinheiro realmente foi movido. Qualquer pessoa na internet pode fazer POST na sua URL de webhook, portanto, o manipulador precisa provar que cada requisição veio da Nomba antes de marcar um pedido como pago ou reembolsar alguém. Ele também precisa lidar com as tentativas de repetição (retry) da Nomba para o mesmo evento.

Use o verificador do SDK oficial; não implemente o HMAC manualmente. A assinatura da Nomba cobre campos específicos unidos por :, e os SDKs também bloqueiam um truque de replay que uma implementação ingênua deixaria passar.

LinguagemVerificação
Node.js / TS (@nombaoss/nomba-node)verifyWebhook(rawBody, headers, signingKey)
Python (nomba)from nomba.webhooks import verify_signature → verify_signature(raw_body, headers, signing_key)
PHP (nombaoss/nomba-php)Nomba\Webhook::verify($rawBody, $headers, $signingKey)

Os imports exatos e os tipos de argumento para cada linguagem estão em references/sdk-setup.md. Cada um retorna o evento analisado ou lança uma exceção (WebhookVerificationError / WebhookVerificationException). Nenhum deles precisa de credenciais de API, apenas da chave de assinatura do webhook obtida no painel da Nomba (Desenvolvedor → Configuração de Webhook). Leia-a de uma variável de ambiente como NOMBA_WEBHOOK_SIGNING_KEY. É um segredo diferente do client secret da API.

O manipulador, passo a passo

  1. Obtenha o corpo bruto. Verifique os bytes exatos que a Nomba enviou. Se um parser de JSON rodar primeiro e você re-serializar o objeto, a assinatura pode parar de corresponder, ou pior, você acaba verificando algo diferente do que está agindo. Cada framework tem uma maneira diferente de obter o corpo bruto; veja references/frameworks.md para a maneira correta, e exclua a rota da proteção CSRF onde o framework a tiver.
  2. Verifique, depois analise. Use o evento que o verificador retorna. Em caso de falha, responda 401 (ou 400) e pare. Não registre o corpo completo ou os cabeçalhos de requisições rejeitadas no nível de info.
  3. Desduplique usando requestId. A Nomba repete entregas, então o mesmo evento pode chegar mais de uma vez. Registre cada requestId processado com uma restrição de unicidade e ignore os que já foram vistos. Retorne 200 também para duplicatas, senão a Nomba continuará tentando.
  4. Confirme rapidamente. Retorne 200 prontamente e faça trabalhos lentos (e-mails, atendimento, atualizações de razão) em um job em segundo plano, indexado por requestId. Manipuladores lentos causam timeouts e reentregas.
  5. Aja no evento usando a tabela abaixo. Combine o evento com seu próprio registro pela referência e verifique se o valor e a moeda correspondem ao que você esperava antes de atender.

O que cada evento significa

event_typeCorrespondênciaAção
payment_successcheckout: data.order.orderReference; conta virtual / transfer in: data.transaction.aliasAccountReference ou transactionIdMarque como pago após verificar data.transaction.transactionAmount (e a moeda) em relação ao seu pedido. Para checkouts tokenizados, armazene data.tokenizedCardData.tokenKey (se presente e não "N/A") com o cliente, apenas no lado do servidor.
payment_failedmesmo que acimaMarque a tentativa como falha; deixe o cliente tentar novamente. Nada foi cobrado.
payment_reversalmesmo que acimaO dinheiro que você recebeu foi estornado. Desfaça o atendimento ou sinalize para revisão.
payout_successdata.transaction.merchantTxRefMarque a transferência ou o pagamento de conta como entregue.
payout_faileddata.transaction.merchantTxRefNão reembolse ainda. A Nomba pode tentar novamente por outra rota. Marque como falha e aguarde.
payout_refunddata.transaction.merchantTxRefO dinheiro está de volta na sua carteira Nomba. Agora é seguro reembolsar ou creditar seu cliente e marcar o pagamento como falho.

Reembolsar em payout_failed (ou em um timeout) em vez de payout_refund é a maneira clássica de comerciantes pagarem clientes duas vezes. Para qualquer evento que você não reconheça, registre-o e retorne 200.

Confirme decisões financeiras com a API. A assinatura da Nomba cobre apenas event_type, requestId, data.merchant.userId, data.merchant.walletId, data.transaction.transactionId, type, time, responseCode e o timestamp. O valor, orderReference, merchantTxRef e o tokenKey do cartão não são assinados. Portanto, antes de atender, reembolsar ou armazenar um token de cartão, consulte novamente a API com o SDK e aja com base na resposta da API: transactions.get({ orderReference }) para pagamentos de checkout (também checkout.getTransaction em produção) e transactions.get({ merchantTxRef }) para pagamentos. A desduplicação usando o requestId assinado impede que uma cópia modificada de um evento que você já processou cause problemas, e a nova consulta cobre o resto.

Proteção contra replay

A desduplicação usando requestId é a principal defesa: uma entrega repetida ou tentada novamente de um evento que você já processou não altera nada.

Os verificadores também podem rejeitar timestamps antigos (toleranceSeconds / tolerance_seconds / o quarto argumento no PHP), mas deixe isso desligado por padrão. A Nomba documenta nomba-timestamp como a hora em que o payload foi enviado, sem dizer se as tentativas automáticas de repetição recebem um novo timestamp. Se elas mantiverem o original, uma tolerância mais curta que a janela de repetição da Nomba rejeitaria tentativas legítimas após uma falha, e pedidos pagos nunca seriam confirmados. Só habilite após confirmar no sandbox que as reentregas carregam um novo timestamp e, em seguida, mantenha-a generosa (por exemplo, uma hora) com os relógios do servidor sincronizados.

Exemplo (Node.js + Express)

import express from "express";
import { verifyWebhook, WebhookEventType } from "@nombaoss/nomba-node";

const app = express();

// Corpo bruto apenas para esta rota; registre antes de qualquer express.json() global.
app.post("/webhooks/nomba", express.raw({ type: "*/*" }), async (req, res) => {
  let event;
  try {
    event = verifyWebhook(req.body, req.headers, process.env.NOMBA_WEBHOOK_SIGNING_KEY!);
  } catch {
    return res.sendStatus(401);
  }

  // Restrição de unicidade em request_id; retorna false se já foi visto.
  const isNew = await webhookEvents.recordOnce(event.requestId, event.event_type);
  if (isNew) await jobs.enqueue("nomba-webhook", event); // processar em segundo plano
  res.sendStatus(200);
});

Python (Flask/FastAPI/Django), PHP (Laravel/plain) e outros frameworks Node estão em references/frameworks.md.

Testes

  • Teste unitário do manipulador com o vetor de teste documentado do SDK: corpo do webhook-fixture.json do SDK, chave SampleSignatureKey123, cabeçalho nomba-timestamp: 2025-09-29T10:51:44Z, nomba-signature: q30yFZDyykoymBf9+mt1wz5UAuLk57raPGPHlGzIv00=. Afirme que uma chave errada, um corpo adulterado e cabeçalhos ausentes são rejeitados, e que um requestId duplicado é processado uma vez.
  • Ponto a ponto: defina uma URL de webhook de teste e uma chave de assinatura no painel, exponha seu servidor local com um túnel e faça pagamentos no sandbox. O painel pode reenviar ou depurar entregas (https://developer.nomba.com/docs/api-basics/troubleshoot-webhooks).

Checklist

  • O corpo bruto é verificado com o SDK, antes de qualquer análise ou lógica de negócio.
  • A chave de assinatura vem do ambiente, não do código.
  • Assinaturas ruins recebem 401/400; nenhuma outra ação acontece.
  • requestId é desduplicado com uma restrição de unicidade; duplicatas ainda recebem 200.
  • Trabalhos pesados rodam em segundo plano; o manipulador retorna 200 rapidamente.
  • O valor e a moeda são verificados em relação ao pedido antes de atender.
  • Reembolsos acontecem apenas em payout_refund (ou uma nova consulta que retorne REFUND).
  • A rota está excluída da proteção CSRF e usa HTTPS.

Habilidades Relacionadas