Como confirmar que uma entrega veio mesmo da SuperSign e não foi alterada, e como trocar o segredo. Visão geral em Webhooks.Verificação da assinatura (HMAC)#
Quando o endpoint tem um segredo de assinatura habilitado, toda entrega leva o header:X-SuperSign-Signature: t=1700000000,v1=<hex>
t é o horário do disparo em segundos (epoch).
v1 é HMAC-SHA256(segredo, "<t>.<corpo cru>") em hexadecimal.
A assinatura é calculada sobre o corpo exato recebido (os bytes do POST), não sobre um objeto reserializado - verifique sobre o raw body, antes de qualquer parse.Passo a passo: (1) leia t e v1 do header; (2) rejeite se |agora − t| for maior que a sua tolerância (ex.: 5 min) - isso barra replay; (3) calcule o HMAC de "<t>.<raw body>" com o seu segredo e compare com v1 em tempo constante.O segredo (whsec_...) aparece uma vez ao gerar/rotacionar na tela do Desenvolvedor, e pode ser revelado por quem administra a integração. Todo endpoint cadastrado hoje já nasce com segredo, devolvido uma única vez na resposta do cadastro. Um endpoint antigo, cadastrado antes de existir o segredo, chega sem o header; para passar a assinar, gire o segredo dele (veja Girar o segredo de assinatura).No exemplo Node, rawBody é o Buffer original, capturado antes do parser
JSON. Não o obtenha reserializando um objeto nem convertendo o Buffer para
string antes do HMAC. A verificação da assinatura não substitui a validação
do JSON e dos campos do evento.Confirmar recebimento somente após gravação durável#
Esqueleto, não servidor pronto. Capture o Buffer antes do parser e use o status
retornado. O adaptador exige inbox durável e worker de retomada conforme o
contrato abaixo; sem implementá-los, o stub lança erro e a resposta é 503.Contrato local do adaptador de inbox#
O recibo { eventId, state: 'PENDING' | 'COMPLETED' } pertence ao adaptador do
seu receptor; não é campo novo do payload nem da API SuperSign. Seu formato não
prova que banco e worker existem. Só o retorne se cumprir este contrato:Use evento.id como chave única. Grave o payload validado e a pendência
PENDING atomicamente, confirmando somente após commit. Não faça consultar
e depois inserir, nem grave no banco e publique em Redis como duas operações
independentes: a queda entre elas pode perder o acionamento do worker.
Uma duplicata preserva o registro e devolve seu estado. PENDING só pode ser
aceito se houver worker implementado que descubra e retome pendências após
falha/reinício. COMPLETED significa trabalho concluído com sucesso. Mesmo
ID com conteúdo divergente exige conferência, nunca sobrescrita silenciosa.
void ou { inserted: false } não comprovam esse contrato. Falha de gravação,
recibo inválido ou ausência da retomada exige erro, para o receptor devolver
503. Não declare concluído apenas para confirmar a duplicata.
O 200 confirma aceitação durável, não conclusão do negócio. Eventos ainda
desconhecidos podem ser registrados e confirmados sem executar ações inventadas.Worker e retomada sem perder pendências#
Um padrão para efeitos inteiramente no mesmo PostgreSQL é usar uma inbox
PENDING e um worker recorrente. Este pseudocódigo é não executável:BEGIN
Selecionar PENDING com SELECT FOR UPDATE SKIP LOCKED.
Aplicar efeitos de negócio no MESMO banco e na MESMA transação.
Marcar COMPLETED somente após sucesso desses efeitos.
COMMIT
O lock é o claim atômico. Não grave um estado de processamento em outra
transação sem mecanismo de recuperação: isso pode prender a linha após crash.
Falha antes do commit reverte efeitos e mantém PENDING; a próxima execução
retoma. O scanner precisa funcionar sem depender de uma notificação em memória
ou publicação perdida. Monitore pendências e falhas permanentes, sem descartá-las
ou afirmar que o exemplo demonstra um worker implantado.Efeitos externos não pertencem a esse padrão transacional. Para email,
pagamento ou chamada de API, use outbox gravada no mesmo commit e idempotência
suportada pelo destino ou reconciliação explícita. ACK externo perdido é resultado
incerto, não autorização para repetir um efeito irreversível. Sem essa
implementação, mantenha o adaptador obrigatório e não prometa exactly-once nem
recuperação automática universal.Ainda assim, para ação irreversível (liberar dinheiro, acesso, documento), confirme o envelope pela rota autenticada como reforço:Valide também event, formato dos IDs e estado esperado. Não exija environment - ele só existe na Sandbox. Nunca confie apenas em campos de contato recebidos no payload.Girar o segredo de assinatura#
{ "data": { "secret": "whsec_..." } }
Esta operação não é idempotente - ela não aceita nem guarda
Idempotency-Key. Cada chamada gera um segredo novo e invalida o
anterior na hora; chamar de novo não devolve o segredo antigo, nunca. Se você
não tiver certeza se a chamada anterior chegou a girar o segredo, chame de
novo: o resultado é sempre um segredo válido e atual. O segredo em texto puro
só aparece nesta resposta - guarde-o agora. A
rotação substitui o segredo na hora: não há período de convivência entre
o antigo e o novo. Da resposta em diante, toda tentativa de disparo - inclusive
as retentativas de entregas que já estavam em curso - sai assinada com o
segredo novo. Como o novo só existe depois da chamada, haverá uma janela entre
a rotação e a atualização do seu verificador em que as assinaturas não
conferem: as entregas continuam chegando normalmente, só a verificação falha.
Para não perder eventos nessa janela, faça seu endpoint responder 5xx quando
a assinatura não conferir (a entrega será retentada) ou reenvie depois as
entregas FAILED com a operação de reenvio (veja Entregas, retentativas e reenvio).Não existe uma operação para revelar um segredo já existente na API
pública (ela existe na tela do Desenvolvedor, para quem administra a conta
pelo navegador). Perdeu o segredo? Rotacione: você recebe um novo na hora.Privacidade e operação#
O payload pode conter nome, e-mail e telefone de signatários; proteja logs e filas.
Não registre sua API Key nem URLs temporárias de download.
Monitore falhas e latência do endpoint.
Responda 2xx a eventos desconhecidos depois de registrá-los: novos tipos de evento podem ser adicionados, e responder 5xx, 404 ou outro status retentável (veja Entregas, retentativas e reenvio) a um evento que você ainda não conhece faz a entrega ser retentada por até ~7 horas. Mantenha o consumidor tolerante a novos campos.
Modificado em 2026-10-04 23:09:47