# Webhooks duplicados e fora de ordem: como evitar ações repetidas

Saiba tratar webhooks duplicados ou atrasados com identidade da ação, persistência, reserva atômica e reconciliação de resultados incertos.

Autoria: Angelo Sebastião Silva Goncalves
Publicado: 2026-10-23T16:23:51.707Z
Revisado: 2026-10-23T16:23:51.707Z
URL canônica: https://nextags.com.br/blog/webhooks-duplicados-fora-ordem-atendimento/

Para evitar ações repetidas a partir de webhooks, registre as entregas recebidas, identifique a ação de negócio e controle quem pode executá-la. A ordem de chegada e a resposta HTTP não bastam para decidir se uma mensagem deve ser enviada ou um registro deve mudar de estado.

O objetivo é que uma reentrega retome a conferência necessária sem repetir um efeito já confirmado. Isso exige armazenamento durável, controle de concorrência e um caminho para resultados incertos. Não é uma promessa de processamento global “exatamente uma vez” entre serviços independentes.

O roteiro a seguir trata a confiabilidade de uma integração. Ele complementa os guias de [Shopify com n8n](/blog/n8n-shopify-nextags-automacoes/) e [Shopify com Make](/blog/integrar-shopify-make-nextags/), sem escolher um orquestrador ou pressupor um deduplicador pronto na Nextags.

## Acompanhe três entregas do mesmo pedido

Considere um pedido P42 e uma ocorrência de pagamento PG7. A automação pretende enviar uma confirmação ao cliente quando essa ação for adequada ao estado da compra.

1. Chega a entrega EV90, informando a confirmação de PG7. A integração registra o recebimento, executa a ação autorizada e obtém confirmação do serviço de destino.
2. EV90 chega novamente. O registro anterior mostra que a ação correspondente foi concluída; a automação não envia outra confirmação.
3. Mais tarde, chega EV12, um evento antigo de criação de P42. Nesse momento, uma consulta à origem já confirma o pedido cancelado. A integração preserva esse estado, em vez de reabrir o atendimento como se a compra tivesse acabado de nascer.

O cancelamento, neste exemplo, foi conferido na origem entre a primeira e a terceira entrega. Ele não é deduzido do nome ou da sequência dos eventos recebidos.

Agora acrescente uma dificuldade: outra entrega, com identificador diferente, também se refere à confirmação de PG7. Comparar apenas os IDs das entregas não impede que ela tente enviar o mesmo aviso. É preciso identificar a ação comercial que já ocorreu.

## Dê identidades diferentes ao evento e à ação

Mantenha no registro quatro referências:

- **Origem e identificador do evento ou entrega:** permitem reconhecer a reentrega conforme o contrato do provedor. Registre também a conta de origem quando a integração atende várias organizações.
- **Alvo de negócio:** pedido, pagamento ou outro objeto ao qual o acontecimento se refere.
- **Identidade da ação:** efeito pretendido, associado à ocorrência de negócio e ao destinatário quando necessário.
- **Estado ou revisão observada:** informação utilizada para decidir se a ação ainda pode acontecer.

No exemplo, a identidade da ação pode combinar a organização, P42, PG7, o aviso de pagamento e o destinatário. Ela permanece estável nas novas tentativas dessa mesma ação. Um novo pagamento ou outro efeito legítimo precisa ser distinguido.

Evite uma chave formada apenas por “pedido + tipo” se isso bloquear ocorrências posteriores válidas. Registre a versão da regra para auditoria, mas não mude automaticamente a identidade da ação a cada edição de texto: isso poderia autorizar um novo envio de um aviso já concluído.

A [documentação de webhooks da Stripe](https://docs.stripe.com/webhooks) descreve reentregas e eventos distintos relacionados ao mesmo objeto e tipo. Também informa que a entrega não garante ordem e que timestamps de criação em segundos não servem para ordenar ou deduplicar esses eventos.

## Confirme o recebimento depois de uma aceitação durável

Antes de confiar nos campos recebidos, valide a autenticidade pelo procedimento oficial do provedor, preservando os bytes exigidos para verificar a assinatura. Vincule a execução ao ambiente e à conta instalada autorizada: um nome de loja recebido não permite operar em outra conta. A assinatura válida também não concede autorização irrestrita. Preserve os segredos fora dos registros compartilhados.

Separe a recepção do trabalho demorado. Grave a entrega autenticada e uma pendência recuperável de processamento, com proteção contra registros duplicados. Só confirme a aceitação depois que esse compromisso durável existir.

Se banco e fila forem serviços separados, preveja como localizar uma entrega aceita que ainda não foi enfileirada. Um disparo mantido apenas na memória, depois da resposta HTTP, pode desaparecer com a interrupção do processo.

A Stripe orienta verificar a assinatura e responder rapidamente antes de lógica complexa que possa causar timeout. Neste desenho, o trabalho posterior encontra o registro persistido. O `2xx` confirma a aceitação da entrega; não comprova o envio de uma mensagem ou a conclusão comercial.

## Reserve a ação sem uma corrida entre executores

Dois processos podem receber trabalho ao mesmo tempo. Ambos consultarem “ainda não executado” e depois enviarem a mensagem não constitui uma proteção suficiente: as duas consultas podem ocorrer antes de qualquer conclusão.

Use uma reserva atômica na persistência compartilhada. Uma restrição de unicidade, operação condicional ou transação precisa decidir qual executor obteve o direito de iniciar aquela ação. Os demais devem encontrar o estado existente e seguir o tratamento correspondente.

Registre estados que distingam, por exemplo, ação pendente, em execução, concluída, dispensada e com resultado incerto. Mantenha a referência do executor e do retorno externo necessários à investigação. A reserva não deve desaparecer quando uma tentativa falha.

Uma execução interrompida também não deve bloquear o trabalho indefinidamente. Defina quem examina reservas abandonadas e quais evidências permitem retomar. Não libere outra execução sem verificar se a anterior ainda pode produzir efeito ou se o destino já realizou a ação.

Esse controle precisa abranger os caminhos que disputam a mesma comunicação. Se dois integradores independentes enviam o aviso sem compartilhar a responsabilidade ou o registro da ação, a proteção de apenas um deles não coordena o outro.

## Decida pelo estado do negócio, não pela chegada

Um evento antigo continua sendo um registro do passado. Ele não deve substituir automaticamente uma condição mais recente confirmada na origem.

Use a revisão ou sequência do objeto quando o provedor oferecer uma referência adequada. Datas ajudam a investigar, mas não criam uma ordem total por si mesmas. Quando faltar uma comparação confiável, consulte a fonte responsável antes de aplicar uma transição que possa regredir o estado.

A [documentação de webhooks da Shopify](https://shopify.dev/docs/apps/build/webhooks) informa que eventos podem chegar fora de ordem, inclusive entre tópicos do mesmo recurso. Ela também recomenda reconciliação porque entregas podem ser perdidas ou tratadas incorretamente. Isso reforça a necessidade de conferir o estado, em vez de depender apenas da sequência recebida.

Na conferência de P42, a criação atrasada fica registrada, mas não desfaz o cancelamento confirmado. Ainda pode haver uma tarefa válida de investigação ou atendimento; ela precisa de uma regra própria, não de uma reabertura automática provocada por um evento antigo.

## Trate resultado incerto antes de fazer replay

Uma chamada ao serviço de destino pode terminar sem resposta enquanto a operação é concluída do outro lado. Nesse caso, timeout não significa necessariamente que nada aconteceu.

Mantenha o resultado como incerto. Consulte o comprovante ou identificador de execução no destino quando disponível. Se o serviço aceitar uma chave de idempotência, use a mesma referência nas tentativas da mesma ação, respeitando o escopo e os limites documentados por ele. Se não houver confirmação suficiente, encaminhe a reconciliação antes de repetir.

Use esta matriz de decisão na revisão:

| Situação | Tratamento esperado | Evidência necessária |
| --- | --- | --- |
| Autenticidade não confirmada | Recusar o processamento de negócio | Resultado da validação da entrega |
| Reentrega de evento conhecido | Consultar o processamento existente | Registro durável e estado da ação |
| Outro evento para a mesma ação concluída | Preservar a conclusão sem novo efeito | Identidade comercial e confirmação anterior |
| Evento antigo diante de estado mais recente | Conferir e evitar regressão indevida | Estado ou revisão confiável na origem |
| Chamada externa com resultado incerto | Reconciliar antes de repetir | Retorno consultável ou análise do responsável |

Replay é uma nova tentativa de processamento, não uma autorização para ignorar as proteções. Ele deve encontrar os mesmos registros e chaves. A Stripe também documenta que um reenvio manual não cancela necessariamente suas tentativas automáticas; os dois caminhos podem coexistir.

## Confira interrupções e concorrência antes de ampliar

Em ambiente autorizado de testes, envie duas entregas iguais simultâneas e confira a quantidade de efeitos no destino. Repita com IDs diferentes para a mesma ocorrência de negócio. Inverta a ordem de criação e atualização e verifique se o estado final permanece correto.

Inclua interrupções depois da persistência, depois da reserva e depois da chamada externa. O resultado esperado muda em cada ponto: recuperar uma pendência não enfileirada, examinar uma execução interrompida ou reconciliar um efeito com resposta perdida.

Por fim, compare registros da integração com a fonte de negócio para encontrar eventos ausentes. Guarde decisões e resultados sem expor informações sensíveis. O [roteiro geral de testes de chatbot](/blog/testes-de-chatbot/) ajuda na validação da jornada; aqui, o foco é a consistência dos efeitos entre sistemas.

Ao desenhar uma [integração por API e webhooks com a Nextags](/integracoes/api-webhooks/), confirme as operações disponíveis e quem mantém recepção, persistência, execução e reconciliação. São responsabilidades do projeto, não propriedades garantidas pela simples existência de uma API. A operação precisa saber o que foi aceito, o que foi concluído e o que ainda exige conferência.

## Fontes
- [Stripe Docs: Receive Stripe events in your webhook endpoint](https://docs.stripe.com/webhooks)
- [Shopify Developers: About webhooks](https://shopify.dev/docs/apps/build/webhooks)