⌘K

Verificar assinaturas de webhooks

Garantir a procedência dos webhooks é crítico. Um invasor poderia enviar um payload falso (p. ex. {"event":"quote.paid"}) para que você libere algo sem que o pagamento seja real. Por isso você deve validar a assinatura.

Como o Cord assina

Cada entrega envia duas assinaturas do corpo bruto, para que você possa migrar sem janela de corte:

  • X-Cord-Signature-V1 (recomendada): t=<unix timestamp>,v1=<hex hmac-sha256 of "{t}.{body}">. Inclui o timestamp dentro do que é assinado, então você pode rejeitar uma entrega antiga reenviada (proteção contra replay). Durante uma rotação de segredo, ela pode trazer dois pares v1=; basta que um deles confira.
  • X-Cord-Signature (legada, mantida por compatibilidade): sha256=<hex hmac-sha256 of the body>, sem timestamp.

Além da assinatura, cada entrega traz X-Cord-Event (nome do evento), X-Cord-Event-Id (id estável do evento, igual nas novas tentativas e em um reenvio manual — use-o para deduplicar), X-Cord-Delivery-Id (muda a cada tentativa) e Idempotency-Key (repete o mesmo valor de X-Cord-Event-Id, para frameworks que o leem automaticamente).

Com o SDK oficial (recomendado)

O @flouviahq/node já traz o verificador pronto: exige X-Cord-Signature-V1, compara em tempo constante e rejeita uma entrega com mais de 300 segundos (configurável com tolerance). A assinatura legada só é aceita se você pedir com allowLegacySignature: true.

import { constructEvent, CordWebhookSignatureError } from '@flouviahq/node';

// Exemplo com um Route Handler do Next.js — req.text() já é o corpo bruto
export async function POST(req: Request) {
  try {
    const event = await constructEvent(await req.text(), req.headers, process.env.CORD_WEBHOOK_SECRET!);
    // event.event, event.data — o catálogo de eventos está no guia de webhooks
    return new Response('ok');
  } catch (err) {
    if (err instanceof CordWebhookSignatureError) return new Response('Invalid signature', { status: 400 });
    throw err;
  }
}

npx @flouviahq/cli init cria essa rota para você, e npx @flouviahq/cli listen permite testá-la na sua máquina com assinaturas reais.

Verificação manual em Node.js (Express)

Se você não usa o SDK, pode verificar a assinatura legada manualmente:

const crypto = require('crypto');

app.post('/webhook/cord', express.raw({ type: 'application/json' }), (req, res) => {
  const received = req.headers['x-cord-signature'] || '';   // "sha256=<hex>"
  const secret = process.env.CORD_WEBHOOK_SECRET;

  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(req.body)            // req.body é o Buffer bruto, sem parsear
    .digest('hex');

  // Comparação em tempo constante (os dois buffers devem ter o mesmo tamanho)
  const ok = received.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));

  if (!ok) return res.status(401).send('Invalid signature');

  const event = req.headers['x-cord-event'];
  const payload = JSON.parse(req.body.toString('utf8'));
  // ... processe o evento (payload.data.id, payload.data.folio, etc.)
  res.status(200).send('Received');
});

Importante: assine sobre o corpo bruto (use express.raw, não express.json), ou o hash não vai coincidir. Para verificar X-Cord-Signature-V1 manualmente, calcule o HMAC sobre "{timestamp}.{body}" em vez de só o corpo, e valide que o timestamp está dentro da sua tolerância — ou use o SDK, que já faz isso por você.


Precisa de mais ajuda?

Fale com a nossa equipe especializada.

Saiba quanto vai pagar

Preços publicados, com a tarifa de cada cobrança sempre visível.

Informações sobre preços →

Comece a construir

Comece a operar e a enviar orçamentos no plano Grátis.

Opções de integração →