8 min de leitura

Trilha de auditoria de webhook: rastreie fluxos de agentes de ponta a ponta

Crie uma trilha de auditoria de webhook que associe ações de agentes, tentativas de saída, callbacks verificados, novas tentativas e o estado final do fluxo sem depender de suposições.

Trilha de auditoria de webhook: rastreie fluxos de agentes de ponta a ponta

Uma ação do agente que inicia um fluxo assíncrono tem duas histórias: a solicitação enviada e o evento que voltou. As equipes costumam registrar a primeira bem o suficiente para responder «o agente chamou a API?» e a segunda para responder «nosso receptor recebeu um webhook?». Durante um incidente, descobrem que ninguém consegue provar que esses registros descrevem o mesmo trabalho.

Uma trilha de auditoria de webhook precisa conectar intenção, autorização, envio, confirmação remota, recebimento, verificação e o estado de negócio que você decidiu aceitar. Tratar uma resposta 200 como o fim do registro é o que torna impossível explicar, três dias depois, um pagamento, uma implantação, um chamado ou uma alteração de acesso.

Uma trilha de auditoria de webhook registra dois fatos diferentes

A trilha deve preservar a diferença entre uma solicitação de ação e uma notificação de evento, porque elas respondem a perguntas diferentes. O lado de saída mostra o que um agente pediu que um serviço remoto fizesse. O lado de entrada mostra o que algum remetente afirmou posteriormente ter acontecido.

Esses fatos podem se referir ao mesmo fluxo, mas têm modos de falha separados. Um agente pode enviar um comando, perder a conexão e enviá-lo novamente. O serviço remoto pode aceitar o comando, executá-lo minutos depois e enviar dois callbacks idênticos. Seu receptor pode verificar o primeiro callback, mas falhar antes de confirmar o estado resultante. Uma linha organizada no log da aplicação não explica essa sequência.

Uso seis tipos de registro ao revisar esses sistemas:

  • Um registro de ação identifica a execução do agente, a autorização humana, a operação solicitada e o alvo pretendido.
  • Um registro de tentativa de saída identifica cada transmissão HTTP, incluindo o resumo da solicitação e a resposta recebida.
  • Um registro de referência remota guarda qualquer identificador retornado pelo provedor, como um ID de tarefa ou operação.
  • Um registro de recebimento captura cada entrega HTTP recebida antes que o processamento de negócio altere qualquer coisa.
  • Um registro de verificação informa exatamente por que o receptor aceitou, rejeitou ou colocou aquela entrega em quarentena.
  • Um registro de transição de estado informa o que o fluxo alterou depois de processar um evento verificado.

Não misture uma tentativa com uma ação. Uma ação pode gerar várias tentativas. Também não misture um recebimento com um evento. Um único evento do provedor pode chegar várias vezes ao seu endpoint. Essa distinção parece excessiva até que um engenheiro precise explicar se uma segunda implantação veio de uma nova tentativa do agente, de uma nova tentativa do cliente HTTP ou do reenvio de um único evento pelo provedor.

A RFC 9110 define POST de forma deliberadamente ampla: o recurso de destino processa a representação de acordo com sua própria semântica. Por isso, uma resposta 202 normalmente significa «aceito para processamento posterior», e até mesmo uma resposta 200 indica apenas que o endpoint concluiu o tratamento da solicitação. Ela não certifica o resultado de negócio remoto. Se o provedor expõe um endpoint separado de status da operação ou um callback, essa evidência posterior determina o resultado.

Um bom registro permite que o revisor leia a história na ordem correta sem deduzir fatos a partir dos timestamps:

agent session sess_7c1e authorized action act_01
act_01 created outbound attempt out_01 with idempotency ref idem_44
remote service accepted out_01 and returned operation op_903
receiver accepted delivery rcp_01 for provider event evt_775
rcp_01 verified its signature and linked evt_775 to op_903
workflow wf_18 moved from pending to completed

Isso é uma cadeia de afirmações, não um único campo de status. Cada afirmação precisa ter sua própria origem e seu próprio horário.

A correlação precisa de mais de um identificador

Um único ID de correlação não resolve o rastreamento de webhooks, porque partes diferentes criam IDs para escopos diferentes. Use um pequeno conjunto de identificadores com propriedade explícita e registre as relações entre eles.

Comece com um ID de ação interno. Crie-o antes de qualquer chamada de rede e associe-o à sessão do agente, à operação solicitada, à decisão de autorização e ao registro de auditoria imutável. Esse ID responde: «Qual instrução do agente causou este trabalho?». Ele não deve mudar quando o cliente tentar novamente.

Crie um ID de tentativa de saída sempre que seu cliente HTTP transmitir algo. Esse ID responde: «Qual tentativa na rede recebeu esta resposta ou erro?». Inclua uma referência de idempotência quando a API remota oferecer suporte a ela. Uma referência de idempotência indica que envios repetidos devem corresponder a uma única operação remota lógica. Ela não informa se uma tentativa HTTP específica chegou ao servidor.

Quando o serviço remoto retornar um ID de operação, persista-o imediatamente junto da tentativa que o recebeu. Se a solicitação aceitar uma referência do cliente ou um campo de metadados, coloque nele o ID da ação depois de confirmar que o provedor o retornará em callbacks ou respostas de status. Nunca coloque um segredo, o nome de um funcionário ou um prompt completo em um campo de referência. Esses campos costumam aparecer em consoles de fornecedores, chamados de suporte e payloads de eventos.

Os callbacks recebidos acrescentam mais dois IDs: o ID do evento do provedor e o ID de recebimento criado por você. O ID do evento do provedor permite eliminar duplicidades daquele remetente. Seu ID de recebimento identifica a entrega HTTP exata recebida pela sua infraestrutura, incluindo cabeçalhos, endereço de origem, se você o guardar, resumo do corpo bruto e resultado da verificação.

A tabela de relações deve ser semelhante a esta:

| Identificador | Criado por | Permanece estável entre novas tentativas? | Responde a |\n|---|---|---:|---|\n| ID da ação | Seu serviço de ações | Sim | Qual solicitação do agente iniciou o trabalho? |\n| ID da tentativa | Seu cliente HTTP | Não | Qual transmissão produziu este resultado? |\n| Referência de idempotência | Seu serviço de ações | Sim | Quais envios significam o mesmo comando remoto? |\n| ID da operação remota | Provedor | Geralmente | Qual tarefa ou objeto remoto mudou? |\n| ID do evento do provedor | Provedor | Sim, para um evento | Qual callback deve ser deduplicado? |\n| ID de recebimento | Seu receptor | Não | Qual entrega recebemos? |

O CloudEvents é útil aqui, mesmo quando um provedor não o envia. A especificação separa id, source, type, subject e time. Essa separação evita um erro recorrente: tratar o ID de um evento como o ID de um fluxo. Um ID de evento identifica um evento de uma origem. Um ID de fluxo identifica o trabalho que você está rastreando. Eles podem apontar para o mesmo objeto remoto, mas não significam a mesma coisa.

Se um provedor fornecer apenas um payload de callback com um ID de objeto, associe-o com cautela. Marque a relação como exata somente quando o ID do objeto vier da resposta de saída registrada ou de uma consulta de status autenticada. Uma correspondência por endereço de e-mail, texto do título, valor ou timestamp é um palpite apresentado como correlação. Não a use em conclusões de auditoria.

Uma resposta 2xx e um callback respondem a perguntas diferentes

Uma resposta 2xx encerra a troca HTTP. Um callback verificado pode confirmar uma alteração de estado remoto. Seu fluxo precisa dos dois e deve descrever honestamente o intervalo entre eles.

Imagine um agente que pede a um serviço de compilação hospedado para publicar um artefato. O serviço retorna 202 e um ID de operação. Seu serviço registra a solicitação como aceita e espera. Dez minutos depois, um callback informa que a publicação falhou porque um repositório downstream rejeitou um manifesto obrigatório. Se o registro de auditoria mudou para «sucesso» no momento da resposta 202, agora ele contradiz a própria evidência do provedor.

Use estados que indiquem qual evidência você tem. Por exemplo:

  1. requested significa que a ação do agente passou pela autorização e criou um item de trabalho.
  2. submitted significa que pelo menos uma tentativa de saída recebeu uma resposta de aceitação ou que um resultado ambíguo recuperável aguarda verificação.
  3. confirmed significa que um callback verificado ou uma resposta de status autenticada estabeleceu o resultado pretendido.
  4. failed significa que uma evidência autoritativa estabeleceu a falha.
  5. unknown significa que você ainda não consegue estabelecer se o lado remoto atuou.

O estado unknown é necessário. As equipes não gostam dele porque deixa os painéis menos bonitos. Eu gosto ainda menos de duplicações silenciosas. Um timeout depois do envio de um POST produz uma entrega ambígua: o sistema remoto pode ter recebido e processado a solicitação, ou pode nunca tê-la visto. Tentar novamente sem um mecanismo de idempotência pode criar duas operações remotas. Chamar a primeira tentativa de «falha» incentiva exatamente esse erro.

Um callback atrasado também não vence automaticamente. Suponha que um agente peça um cancelamento depois do comando inicial e que seu fluxo interno registre um cancelamento válido. Um callback de conclusão que chega depois pode relatar o que aconteceu remotamente antes de o cancelamento entrar em vigor. Preserve-o, verifique-o, associe-o e registre o conflito. Não deixe um handler genérico substituir um estado terminal de cancelamento apenas porque «concluído» ocupa uma posição superior no enum de alguém.

Escreva uma regra de transição para cada tipo de callback. Uma aprovação de pagamento, uma conclusão de compilação, um evento de provisionamento de usuário e uma confirmação de exclusão não devem usar as mesmas transições. A regra deve indicar quais estados anteriores permitem a transição, que evidência o handler exige e se um operador precisa resolver um conflito.

O receptor precisa preservar a evidência antes de analisá-la

Seu receptor deve capturar a entrega bruta, verificá-la e eliminar duplicidades antes de executar um efeito colateral. Analisar o JSON primeiro e armazenar apenas campos selecionados destrói evidências quando o parser, o esquema ou o código da aplicação se mostrarem incorretos.

No momento do recebimento, registre os itens a seguir em um armazenamento protegido de eventos:

  • O ID de recebimento e o timestamp do servidor.
  • O método da solicitação, a rota, os cabeçalhos selecionados e um resumo criptográfico do corpo bruto exato.
  • A identidade do remetente esperado e o esquema de verificação aplicado.
  • O ID do evento do provedor, se o payload fornecer um, além do tipo de evento analisado.
  • A decisão: aceito, duplicado, rejeitado ou colocado em quarentena, com um código de motivo.

Mantenha os payloads brutos apenas durante o período de retenção justificado pelas necessidades de investigação e conformidade. Um resumo geralmente basta para provar que dois payloads são iguais. Se guardar um corpo, criptografe-o, restrinja o acesso e evite copiá-lo para logs comuns da aplicação. Webhooks costumam conter dados pessoais, metadados de repositórios, endereços e notas internas. Um armazenamento de auditoria que vaza o payload é um risco, não uma evidência.

A verificação da assinatura precisa operar sobre o corpo exatamente como foi assinado pelo remetente. Uma camada de middleware que analisa o JSON, o reformata e depois verifica os bytes reformados rejeitará entregas legítimas ou, pior, permitirá tratamentos inconsistentes. Leia com atenção a documentação de verificação do provedor. Alguns esquemas assinam timestamp + "." + raw_body; outros assinam apenas o corpo bruto; outros usam assinaturas assimétricas e chaves públicas rotativas.

Para um esquema HMAC genérico que assina apenas o corpo bruto, este comando mostra o formato do resumo esperado a partir dos bytes sem alterações:

printf '%s' "$RAW_BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET"
# SHA2-256(stdin)= 4d3c...hex digest...

Isso é um diagnóstico, não um substituto para a string canônica exata do provedor. Se o provedor incluir um timestamp ou prefixo de versão, copiar o comando genérico produzirá o resultado errado. Esse erro aparece com frequência porque os engenheiros verificam uma aproximação conveniente em vez do algoritmo documentado pelo remetente.

A validade da assinatura não impede reenvios. Se o remetente fornecer um timestamp assinado, rejeite entregas fora de uma janela curta, permitindo uma margem para a diferença de relógio medida. Depois, registre os IDs dos eventos do provedor em um armazenamento persistente de eliminação de duplicidades antes de chamar o trabalho downstream. Se você não puder confiar em um ID de evento, elimine duplicidades usando um resumo definido pelo remetente e um período de retenção adequado, sabendo que dois eventos legítimos e idênticos podem então exigir tratamento especial.

Retorne uma resposta HTTP somente depois de tornar persistente a decisão sobre o recebimento. Se você retornar sucesso primeiro e falhar antes de gravar a deduplicação, o remetente poderá tentar novamente e seu handler poderá processar o mesmo evento duas vezes. Esse bug fica escondido em testes de baixo volume e aparece justamente nas condições de indisponibilidade em que o tráfego de webhooks aumenta.

As novas tentativas mostram onde seus registros são vagos demais

Coloque a aprovação antes das ações
Um novo processo de agente precisa de aprovação por sessão antes que o Sallyport permita chamadas de API ou SSH.

Novas tentativas são um comportamento normal, não um caso raro, e cada camada pode tentar novamente de forma independente. Agentes tentam novamente depois de um timeout. Bibliotecas HTTP repetem uma falha de conexão. Provedores de API repetem callbacks. Consumidores de filas repetem um handler que falhou. Um registro que reduz tudo a «contagem de tentativas: 3» não ajuda ninguém.

Analise uma falha que já vi de várias formas. Um agente pede a criação de um registro de acesso remoto. O cliente envia um POST e sofre timeout depois que os bytes saem da máquina. O serviço remoto cria o registro e coloca um callback na fila. O framework do agente tenta novamente porque viu um timeout. A segunda solicitação cria outro registro porque a camada de ação gerou uma nova referência de idempotência a cada tentativa. Os dois callbacks chegam. O receptor usa apenas um endereço de e-mail para associá-los, decide que são duplicados e suprime o segundo. A página de auditoria mostra uma solicitação concluída. O serviço remoto agora tem dois registros de acesso.

Cada componente se comportou de uma maneira plausível. O sistema falhou porque não preservou um comando lógico entre as fronteiras de novas tentativas.

Corrija a sequência:

  1. Gere o ID da ação e a referência de idempotência uma única vez, antes da primeira tentativa de saída.
  2. Registre cada tentativa separadamente, incluindo timeouts e erros de transporte.
  3. Em caso de ambiguidade, consulte o provedor pela referência de idempotência ou pela referência do cliente antes de emitir outro comando.
  4. Aceite cada callback autenticado como um recebimento e elimine duplicidades apenas pelo ID do evento do provedor, não pelo próprio objeto remoto.
  5. Compare a quantidade esperada de objetos remotos com a ação registrada antes de declarar o fluxo concluído.

A primeira verificação de idempotência pertence ao remetente, e a segunda, ao receptor. Elas resolvem problemas diferentes. A idempotência do remetente impede comandos remotos duplicados. A deduplicação do receptor impede o processamento repetido de um único evento remoto. As equipes costumam instalar uma e presumir que obtiveram a outra.

Não use o horário de chegada como ordem dos fatos de negócio. Os provedores podem entregar eventos atrasados ou fora de ordem, e sua própria fila pode atrasar o processamento. Armazene pelo menos três horários: quando seu serviço de ações criou a ação, quando o cliente HTTP enviou a tentativa ou recebeu a resposta e quando o receptor recebeu o callback. Preserve separadamente o horário de evento declarado pelo remetente. O relógio do remetente é uma evidência desse remetente, não o seu relógio.

A autorização precisa atravessar a fronteira assíncrona

A aprovação humana para uma ação do agente deve estar ligada à própria ação, não ao callback que vier depois. Um callback traz informações sobre um trabalho remoto. Ele nunca deve obter silenciosamente autoridade para iniciar uma nova operação privilegiada apenas por compartilhar um campo de correlação com uma solicitação aprovada.

Isso importa quando callbacks podem conter URLs, nomes de objetos, metadados controlados pelo usuário ou instruções seguidas por um handler interno. Um projeto problemático comum recebe um evento «tarefa concluída» e permite que um worker de automação genérico busque uma URL de resultado ou execute um comando posterior usando credenciais amplas. A aprovação original do agente abrangia o envio de uma tarefa, não um conjunto aberto de ações incorporadas ao evento.

Registre a ação autorizada em termos concretos: sessão do ator, endpoint solicitado ou modelo de comando SSH, escopo do alvo, identidade da credencial, resultado da aprovação e horário da aprovação. Para cada chamada de saída, aponte para esse registro de autorização. Para cada callback, aponte para a ação somente depois da verificação e da correlação. A direção importa. Uma solicitação recebida não deve procurar no banco de dados qualquer aprovação conveniente e aproveitá-la.

O Sallyport mantém as credenciais do agente fora do processo e registra tanto as execuções dos agentes quanto as chamadas individuais. Isso facilita a preservação da metade de saída dessa evidência. O receptor do callback ainda precisa de seus próprios registros de recebimento e fluxo, porque um diário de ações HTTP não consegue saber se um sistema remoto enviou posteriormente um evento válido.

Use credenciais separadas para as duas direções. A credencial que autoriza sua chamada de saída à API normalmente não deve verificar assinaturas recebidas, e o segredo de verificação de entrada não deve autorizar um handler de callback a chamar APIs externas arbitrárias. A separação limita os danos quando uma rota do receptor, uma dependência ou um destino de logs apresenta problemas.

A evidência de adulteração deve cobrir as relações, não apenas as chamadas

Evite a proliferação de regras de política
A hierarquia fixa de decisões usa o bloqueio do cofre, a aprovação da sessão e aprovações por chave em vez de regras de política.

Um registro somente de acréscimo das chamadas de saída ajuda, mas não prova as decisões de correlação tomadas depois. Um operador ou um bug da aplicação pode associar o callback errado à ação errada sem alterar nenhum dos registros HTTP originais.

Transforme a correlação em um evento de auditoria de primeira classe. O evento deve incluir o ID da ação, o ID de recebimento, a base da relação, o ator ou processo que tomou a decisão e um resumo dos campos usados. Use bases explícitas, como remote_operation_id_exact, client_reference_exact, authenticated_status_lookup ou manual_review. Não escreva apenas «correspondente» e deixe o investigador adivinhar.

Um log encadeado por hashes pode mostrar que os registros não foram alterados depois de criados, desde que você proteja o caminho de acréscimo e mantenha pontos de verificação. Ele não prova que a aplicação tomou a decisão correta no momento. É saudável declarar essa limitação claramente. A evidência contra adulteração fornece um relato estável do que o sistema registrou; ela não transforma uma correlação fraca em fato.

O log de auditoria criptografado e encadeado por hashes do Sallyport pode ser verificado offline com sp audit verify, mesmo sem uma chave do cofre. Use esse tipo de verificação para os registros de ações e mantenha uma referência imutável equivalente, no armazenamento do fluxo, aos IDs relevantes de ação e chamada.

Para fluxos de alto impacto, adicione um trabalho de reconciliação que compare três grupos: ações enviadas, operações remotas conhecidas pelo provedor e callbacks aceitos pelo receptor. O trabalho deve criar um registro de exceção para um item sem par, em vez de fechá-lo automaticamente. Um callback ausente pode significar uma indisponibilidade do provedor, um endpoint incorreto, uma falha na rotação de assinatura ou um bug no fluxo. Você precisa de evidências antes de precisar de otimismo.

A observabilidade deve permitir que o investigador refaça a decisão

Verifique o histórico de saída
Use o diário de atividades para preservar as chamadas feitas pelo agente que iniciaram seu fluxo de trabalho com webhooks.

Um investigador deve conseguir começar por qualquer identificador e reconstruir o fluxo sem acesso privilegiado a prompts dos agentes ou segredos de API. Defina os caminhos de busca antes de colocar a integração em produção.

A partir de um ID de ação, o registro deve mostrar a sessão do agente, a autorização, o rótulo da credencial, o formato da solicitação após a ocultação de dados, todas as tentativas, referências remotas, recebimentos relacionados e o estado terminal do fluxo. A partir de um ID de evento do provedor, deve mostrar cada entrega desse evento, os resultados da verificação, a deduplicação, a operação relacionada e as mudanças de estado. A partir de um objeto de negócio interno, deve mostrar a evidência exata que o associou a uma ação do agente.

Use campos estruturados, não uma única string narrativa. Um contrato de evento útil pode ser copiado para uma revisão de esquema ou pipeline de logs:

{
  "record_type": "callback_receipt",
  "receipt_id": "rcp_01J...",
  "received_at": "2025-03-08T22:14:31Z",
  "sender": "build-service",
  "provider_event_id": "evt_775",
  "event_type": "publication.finished",
  "raw_body_sha256": "4d3c...",
  "signature": {"scheme": "hmac-sha256", "result": "valid"},
  "correlation": {
    "action_id": "act_01J...",
    "remote_operation_id": "op_903",
    "basis": "remote_operation_id_exact"
  },
  "processing": {"deduplication": "new", "result": "completed"}
}

O resumo do corpo, o resultado da verificação e a base da correlação fazem muito mais que um status: success vago. Eles permitem testar afirmações. Se um provedor contestar um callback, compare o resumo preservado. Se um engenheiro contestar uma correspondência, examine a base. Se uma duplicata causou efeitos colaterais, verifique se o receptor gravou o registro de deduplicação antes de despachar o trabalho.

Evite registrar cabeçalhos de autorização, tokens bearer, chaves privadas, segredos de assinatura ou URLs completas que contenham credenciais. Oculte valores de consulta quando contiverem dados sensíveis, mas preserve identidade suficiente para distinguir dois alvos. Já vi equipes ocultarem uma URL até ela se tornar inútil e depois não conseguirem dizer se um agente contatou produção ou um endpoint de teste. Armazene um host normalizado, um modelo de rota, o método e um identificador de alvo cuidadosamente limitado.

Crie o rastreamento antes que os agentes façam chamadas assíncronas

Defina os identificadores, as regras de recebimento e as transições de estado antes de dar a um agente uma ação que inicie um trabalho assíncrono. Implementá-los depois de uma contestação é caro, porque a evidência ausente nunca existiu.

Faça um exercício deliberado de falha. Envie uma ação de teste inofensiva, force o cliente a sofrer timeout depois da transmissão, se o ambiente de teste permitir, reenvie o mesmo callback, envie um callback com assinatura inválida e entregue um callback válido depois que o fluxo entrar em um estado terminal. Verifique se o registro de auditoria explica cada resultado sem que uma pessoa precise preencher lacunas de memória.

Se seu sistema não consegue responder «qual ação autorizada causou este callback, com base em qual evidência exata e o que fizemos com ele?», então ainda não tem uma história de auditoria para webhooks. Tem dois conjuntos de logs que por acaso compartilham um relógio.

FAQ

O que é uma trilha de auditoria de webhooks?

Uma solicitação de saída prova que seu agente ou serviço tentou fazer uma chamada. Um callback prova que outro sistema enviou posteriormente uma mensagem ao seu receptor. Nenhum dos dois registros, sozinho, comprova o resultado completo do negócio. Por isso, relacione-os com identificadores persistentes e registre a decisão do receptor.

Uma resposta HTTP bem-sucedida prova que uma ação do agente foi concluída?

Geralmente, não. Uma resposta 2xx indica que o servidor receptor aceitou a solicitação HTTP de acordo com as regras daquele endpoint. O sistema downstream ainda pode rejeitar o trabalho, colocá-lo em uma fila para revisão, tentar novamente ou enviar um estado final diferente em um callback.

Quais IDs devo armazenar para um webhook acionado por um agente?

Mantenha o ID da sessão do agente, o ID da ação, o ID da tentativa de saída, o ID de correlação do provedor, o ID do evento de callback e o ID do objeto de negócio. Cada um identifica algo diferente. Perder qualquer um deles torna muito mais difícil investigar novas tentativas e duplicidades.

Como devo lidar com um callback que chega depois que um fluxo foi cancelado?

Não marque a ação como concluída no primeiro callback correspondente. Primeiro, verifique o callback, elimine duplicidades, associe-o à solicitação correta e aplique a transição de estado permitida pelo fluxo. Um callback de aprovação que chega depois de um cancelamento deve ser tratado como evidência, não como permissão para reabrir o trabalho.

Devo salvar payloads completos de webhooks nos registros de auditoria?

Armazene um resumo do corpo bruto, os cabeçalhos usados na verificação, o resultado da verificação, o horário de recebimento e os campos analisados usados no roteamento. Limite o acesso aos payloads brutos, pois os callbacks costumam conter dados de clientes ou referências internas. Seu registro de auditoria deve preservar a prova sem se transformar em um arquivo de dados sem controle.

Posso usar o ID de evento do provedor como meu único ID de correlação?

O ID de evento do provedor só é exclusivo dentro do fluxo de eventos daquele provedor, e alguns provedores reenviam deliberadamente o mesmo evento. Use-o para eliminar duplicidades dentro dessa origem. Depois, mantenha seu próprio ID imutável de recebimento e um identificador separado de solicitação ou fluxo para correlação.

Os callbacks de webhook são entregues exatamente uma vez?

Não. Muitos sistemas de webhook prometem entrega pelo menos uma vez, o que significa que duplicidades são esperadas. Crie um registro persistente de eliminação de duplicidades antes de executar efeitos colaterais e faça o handler retornar a resposta de sucesso apropriada para uma duplicata conhecida.

Como verificar um webhook recebido com segurança?

Verifique a assinatura usando o corpo da solicitação sem modificações, antes de analisá-lo ou normalizá-lo. Quando o remetente fornecer um timestamp assinado, aplique também uma janela de tempo, identifique a origem esperada e trate a detecção de reenvio como algo separado da verificação da assinatura.

Como distinguir uma nova tentativa de uma segunda ação do agente?

Use o ID da tentativa registrado e a referência de idempotência para descobrir se o remetente repetiu o mesmo comando lógico ou criou um segundo comando. Depois, compare o valor de correlação do provedor, o resumo do payload e o objeto de negócio resultante. O tempo, sozinho, é uma evidência fraca, pois filas e novas tentativas de rede o distorcem.

De quais evidências os auditores precisam para fluxos assíncronos de agentes?

Os auditores precisam de um relato cronológico que explique a autorização, o uso das credenciais, a intenção de saída, as tentativas de entrega, os recebimentos verificados e o estado final. Um diário de ações com evidência de adulteração ajuda a estabelecer o que o agente fez, mas o registro do fluxo ainda precisa conectar essa ação aos eventos assíncronos fora do gateway.

Sallyport

O Sallyport executa chamadas de API e comandos SSH pelo seu agente de IA. As chaves ficam em um cofre local no seu Mac; você aprova cada execução e toda ação vai para um registro selado.

© 2026 Sallyport · Código aberto sob Apache-2.0 · Oleg Sotnikov