Automação Comercial

O bug que criou 346 grupos duplicados no Pipedrive (e o que aprendi sobre idempotência)

Um erro no código criou 346 grupos duplicados no Pipedrive num final de semana. Conto o que aconteceu, como resolvi e o conceito que aprendi tarde.

Ilustração editorial em tons de azul representando o artigo: O bug que criou 346 grupos duplicados no Pipedrive (e o que aprendi sobre idempotência)
Neste post
  1. O que aconteceu exatamente?
  2. Como descobri (o momento “eita”)
  3. Como limpei a bagunça
  4. O que causou (a explicação sem jargão)
  5. O que é idempotência e por que vc deveria se importar (mesmo sem saber programar)
  6. Como resolvi na origem
  7. O que não funcionou na primeira tentativa de correção
  8. O que aprendi que uso até hoje
  9. FAQ

Na segunda-feira de manhã abri o Pipedrive e tinha 346 grupos criados. Todos duplicados, todos inúteis, todos criados pelo meu próprio código num final de semana em que achei que estava com tudo sob controle. Esse post é sobre o erro, a limpeza e o conceito que deveria ter aprendido antes de colocar qualquer integração em produção.

O que aconteceu exatamente?

346 grupos no Pipedrive. Criados entre sábado à noite e domingo. Nenhum deles deveria existir.

A integração era simples no papel: toda vez que uma conversa nova chegava pelo WhatsApp (via Z-API e ChatGuru), o código criava ou atualizava um “grupo” no Pipedrive pra organizar os contatos por origem. Funcionava bem nos testes. Coloquei em produção na sexta, fui descansar.

O que eu não sabia é que o webhook do ChatGuru estava com retry automático ativado. Cada mensagem que chegava e não recebia confirmação em tempo hábil era reenviada. E o código, em vez de verificar se o grupo já existia antes de criar, simplesmente criava um novo toda vez. Três reenvios por mensagem, pico de conversas no fim de semana, resultado: 346 grupos com nomes iguais ou quase iguais entupindo o CRM.

O dado que mais dói: levei aproximadamente 4 horas pra limpar manualmente o que o código fez em menos de 48 horas.

Como descobri (o momento “eita”)

Cheguei na segunda de manhã pra revisar o pipeline antes de uma reunião. Abri o Pipedrive, fui na aba de grupos pra conferir uma coisa rápida. A lista não acabava.

Primeiro pensei que era bug de interface. Recarreguei. Continuava igual. Fui filtrar por data de criação e vi: sábado às 23h, dezenas de grupos criados em sequência com diferença de segundos entre eles. Todos com o mesmo nome base.

Aí o estômago virou. Não foi alguém invadindo o sistema, não foi erro do Pipedrive, não foi nada externo. Era o meu código fazendo exatamente o que eu tinha programado, só que sem o controle que eu achei que tinha colocado lá.

Fui checar os logs do webhook. A resposta HTTP de confirmação estava demorando mais que o timeout configurado no ChatGuru. O sistema interpretava como falha e reenviava. O código recebia, criava grupo novo, confirmava. Aí reenviava de novo. Criava de novo.

Como limpei a bagunça

Não tinha atalho elegante. A API do Pipedrive permite deletar grupos um por um ou em lote pequeno. Não tem “deletar todos os grupos com nome X” de uma vez só.

Escrevi um script em Node que paginava todos os grupos, identificava os duplicados por nome, mantinha o mais antigo (que tinha os dados reais) e deletava os outros. Rodei em modo de simulação primeiro (dry-run) pra garantir que não ia apagar coisa errada. Levou umas duas horas só pra fazer o script funcionar direito.

Depois rodei de verdade. Mais quarenta minutos de execução. API do Pipedrive tem rate limit e o script respeitava, então foi devagar mesmo. No final sobraram 23 grupos legítimos. Os outros 323 foram deletados.

O custo real não foi o tempo de limpeza. Foi saber que aqueles grupos tinham sido criados durante um fim de semana em que eu poderia ter recebido leads reais. Qualquer relatório ou automação que dependesse desses grupos estava contaminada com lixo.

O que causou (a explicação sem jargão)

Imagina que vc tem um funcionário e dá a instrução: “sempre que um cliente novo ligar, cria uma pasta pra ele.” Só que vc não diz “verifique se a pasta já existe antes de criar.” O funcionário é literal: ligou de novo? Nova pasta. Ligou mais uma vez? Mais uma pasta.

É exatamente isso que o meu código fazia. A instrução era “criar grupo.” Não era “criar grupo se não existir.” Parece detalhe. Não é.

O que piorou foi o retry automático do webhook. Quando um sistema manda uma mensagem e não recebe confirmação, ele manda de novo. É um comportamento saudável e esperado em integrações, faz parte do design de sistemas distribuídos. O problema é que meu código não estava preparado pra receber a mesma mensagem duas vezes sem criar duplicata.

Na prática: a mesma mensagem chegou em média 3 a 4 vezes por causa de timeouts. Cada chegada criou um grupo. Multiplica pelo volume de conversas no fim de semana e chega em 346.

O que é idempotência e por que vc deveria se importar (mesmo sem saber programar)

Idempotência é uma palavra feia pra um conceito simples: a mesma operação, executada N vezes, produz o mesmo resultado que executada uma vez só.

Exemplo prático: apertar o botão de fechar a porta do elevador uma vez ou dez vezes muda alguma coisa? Não. A porta fecha do mesmo jeito. Isso é uma operação idempotente.

Agora imagina um botão “finalizar compra” que não é idempotente. Vc clica, a internet trava, vc clica de novo achando que não foi. Duas cobranças. É exatamente o tipo de bug que faz cliente te ligar furioso numa segunda de manhã.

Em integrações de WhatsApp com CRM, o problema aparece em três lugares clássicos: criação de contato (cria duplicado), criação de deal (abre deal duplicado) e, no meu caso, criação de grupos ou categorias. Qualquer operação que depende de “primeiro verifica se existe, só cria se não existe” precisa ser pensada com cuidado.

A boa notícia: vc não precisa saber programar pra exigir isso de quem monta sua integração. Basta fazer a pergunta certa: “se essa ação rodar duas vezes por causa de um erro de rede, o que acontece?”

Sua integração WhatsApp + Pipedrive está criando duplicatas?

A gente faz um mapeamento do seu processo comercial e identifica os pontos de falha antes de colocar em produção.

Quero o mapeamento

Como resolvi na origem

A correção tinha três partes.

Primeira: trocar INSERT por UPSERT. Em vez de simplesmente criar o grupo, o código passou a verificar se já existe um grupo com aquele identificador único. Se existe, atualiza. Se não existe, cria. Em SQL isso se chama ON CONFLICT DO UPDATE ou ON CONFLICT DO NOTHING, dependendo do caso. Na prática, significa que a mesma mensagem chegando 10 vezes vai resultar em exatamente 1 grupo, não 10.

Segunda: usar agent_request_id como chave de idempotência. Cada mensagem que chega pelo webhook agora tem um identificador único que eu armazeno. Se o mesmo ID chegar de novo, o sistema reconhece, retorna “ok” pro webhook (pra ele parar de reenviar) e não faz mais nada. O cache fica ativo por 24 horas, que é mais que suficiente pra cobrir qualquer janela de retry razoável.

Terceira: confirmar o webhook mais rápido. O timeout estava configurado pra 3 segundos. Meu código demorava às vezes 4-5 segundos por causa de chamadas encadeadas à API do Pipedrive. Resolvi separar a confirmação do webhook do processamento em si: confirmo imediatamente, processo na sequência. O ChatGuru para de reenviar e o processamento acontece sem pressão de tempo.

O que não funcionou na primeira tentativa de correção

Minha primeira tentativa foi só adicionar uma verificação antes de criar: “busca grupo por nome, se achar, não cria.” Pareceu lógico. Não funcionou.

O problema é que a verificação e a criação não eram atômicas. Em linguagem simples: o código verificava se o grupo existia (não existia), começava a criar, mas se dois eventos chegassem ao mesmo tempo, ambos passavam pela verificação antes de qualquer um terminar de criar. Resultado: ainda criava duplicatas, só menos.

Isso tem nome técnico: race condition. E é por isso que a solução correta é no banco de dados ou na camada de deduplicação, não na lógica do aplicativo. O banco de dados tem como garantir que só um processo por vez completa a operação pra um dado identificador. O aplicativo não tem essa garantia quando roda em paralelo.

Levei um dia inteiro testando a solução errada antes de entender por que ela não resolvia completamente.

O que aprendi que uso até hoje

Primeiro: toda integração que recebe webhook precisa ter deduplicação por ID antes de qualquer processamento. Não é opcional, não é “nice to have.” É o mínimo.

Segundo: testar com reenvio deliberado antes de ir pra produção. Hoje, antes de liberar qualquer integração, mando a mesma mensagem de teste 5 vezes seguidas e verifico o resultado. Se criar 5 registros, está errado. Se criar 1, está certo.

Terceiro: rate limit e retry são comportamentos normais e esperados de sistemas de integração. Meu código precisa estar preparado pra isso, não esperar que “vai funcionar direitinho” porque funcionou nos testes.

Quarto, e talvez o mais importante: o custo de um bug de duplicação não é só técnico. É a confiança no CRM. Quando a equipe de vendas encontra registros duplicados sem explicação, ela para de confiar nos dados. E CRM sem confiança é planilha cara.

O bug dos 346 grupos me custou um fim de semana de limpeza e alguns meses de paranoia toda vez que subia uma integração nova. Hoje encaro como a melhor aula sobre idempotência que eu poderia ter tido, porque foi real e doeu no bolso do tempo.

Faz sentido?


FAQ

Por que o Pipedrive não impede a criação de grupos duplicados automaticamente?

O Pipedrive não tem como saber o que é duplicado pro seu contexto. Ele segue a instrução que chega via API: “criar grupo com esse nome.” Se vc manda a mesma instrução 346 vezes, ele cria 346 grupos. A responsabilidade de controlar duplicatas é da camada de integração, não do CRM. Isso vale pra qualquer CRM, não só o Pipedrive.

Preciso saber programar pra evitar esse tipo de problema?

Não. Vc precisa saber fazer as perguntas certas pra quem programa pra vc. Pergunta antes de qualquer integração ir pro ar: “o que acontece se essa ação rodar duas vezes?” e “como o sistema lida com reenvio de webhook?” Se a pessoa não souber responder, é sinal de que precisa pensar melhor antes de colocar em produção.

Quanto tempo leva pra limpar 346 registros duplicados no Pipedrive?

Depende de como vc faz. Manual, item por item pela interface, levaria dias. Com um script que usa a API do Pipedrive pra identificar e deletar em lote (respeitando o rate limit), levou cerca de 3 horas entre escrever, testar e executar. A API do Pipedrive tem documentação boa pra esse tipo de operação de limpeza.

O ChatGuru ou a Z-API têm alguma configuração pra evitar retry excessivo?

Sim. O ChatGuru permite configurar o timeout e o número máximo de retentativas por webhook. O padrão costuma ser conservador (3-5 tentativas), o que é razoável. O problema não estava no retry em si, que é um comportamento correto. O problema era que meu código não estava preparado pra receber a mesma mensagem mais de uma vez. As duas partes precisam estar alinhadas.

Esse tipo de bug só acontece com Pipedrive e WhatsApp?

Não. É um problema de design de integração que aparece em qualquer combinação de sistemas com webhook. HubSpot + WhatsApp, RD Station + formulário, qualquer coisa com retry automático + código sem deduplicação vai ter o mesmo problema. A solução de usar um identificador único e verificar antes de processar é universal. Muda a implementação técnica, o conceito é o mesmo.

E

Eric Luciano

CEO da Expert Integrado. Mentor G4 Educação. Educador há 25 anos. Aplica IA pra devolver tempo ao empresário de PME.

Quer um Super SDR rodando no seu WhatsApp?

No mapeamento gratuito eu mostro como montar a qualificação automática e o follow-up do seu funil sem contratar mais gente.

Fazer o mapeamento gratuito Ou me acompanhe no Instagram: @ericluciano