Custom code na HubSpot: secrets, limites e retries na prática
Custom code actions são a válvula de escape dos workflows da HubSpot: quando as ações nativas não dão conta da sua lógica, você insere um bloco de JavaScript ou Python e o workflow o executa para cada registro inscrito. Elas também são o lugar onde as automações quebram silenciosamente em produção, porque três coisas sobre elas são amplamente mal compreendidas: como os secrets chegam de fato ao seu código, quais são os limites reais de execução e o que a HubSpot faz (e não faz) quando o código falha. Este guia cobre as três, com os números exatos e os padrões que usamos depois de anos construindo e resgatando essas ações. Se automação confiável é a fundação de uma boa operação de receita, e é, vale entender esse assunto tão bem quanto o próprio conceito de Revenue Operations.
Um pré-requisito antes de qualquer coisa: custom code actions exigem Operations Hub Professional ou Enterprise. Se a ação não está aparecendo no seu editor de workflow, essa é a primeira coisa a checar, não o seu código.
O que uma custom code action pode (e não pode) fazer
Uma custom code action é uma pequena função serverless que a HubSpot executa dentro de um workflow. Você recebe os dados do registro inscrito como entrada, pode chamar qualquer API (da HubSpot ou externa) e pode retornar campos de saída que as ações seguintes do workflow consomem. O ambiente, na prática:
- Linguagens: Node.js ou Python, escolhidos por ação no editor. O suporte a Python ainda está oficialmente em beta, então Node.js segue como o padrão mais seguro para qualquer coisa crítica de negócio.
- Bibliotecas pré-carregadas: o essencial já vem pronto, incluindo
axios(^1.2), o cliente oficial@hubspot/api-client(^10),lodash,asynce um clienteredisno Node (erequestsmais o cliente da HubSpot no Python). A lista completa e atual, com versões, está na documentação oficial de custom code; você não consegue instalar mais nada via npm, então planeje em torno do que é fornecido. - Execução sem estado: nada persiste entre execuções. Nada de variáveis globais, arquivos locais ou memória do registro anterior. O estado precisa viver em outro lugar: propriedades do CRM, um sistema externo ou uma instância Redis sua (o cliente
redisvem pré-carregado no Node, o que o torna um lugar prático para guardar locks e chaves de deduplicação; mais sobre isso na seção de retries). - Campos de saída: os valores que você retorna ficam disponíveis para as ações seguintes (ramificações, cópias para propriedades), e é assim que o custom code se compõe com o resto do workflow.
O modelo mental certo: custom code actions servem para lógica cirúrgica em um registro por vez: scoring com regras de negócio, formatação e validação, chamada a uma API externa para enriquecimento, criação de um objeto associado com uma lógica que as ações nativas não alcançam. Elas não são um pipeline de dados. Para trabalhos pesados ou demorados, orquestre por fora (uma fila ou uma plataforma de automação como o n8n) e deixe o workflow apenas disparar; nosso guia de integração da HubSpot com o n8n cobre exatamente essa arquitetura.
Secrets: credenciais do jeito certo (e a pegadinha que retorna undefined)
Secrets são o mecanismo da HubSpot para manter credenciais fora do seu código. Você os cria no editor da custom code action e eles chegam em tempo de execução como variáveis de ambiente: process.env.MEU_SECRET no Node, os.getenv('MEU_SECRET') no Python. O valor de um secret é limitado a 1.000 caracteres, o que é de sobra para um token, mas descarta enfiar ali uma chave privada ou um JSON inteiro. Três regras mantêm isso limpo:
- Nunca deixe um token fixo no bloco de código. O código é visível para todo usuário que pode editar workflows, é clonado junto quando os workflows são clonados, e rotacionar um token hardcoded significa caçar cada ação em que ele foi colado. Os secrets centralizam isso.
- Selecione o secret em cada ação que o usa. Essa é a pegadinha clássica: criar o secret não basta. Cada custom code action tem sua própria lista de secrets selecionados, e um secret que você não adicionou nesta ação simplesmente não existe no ambiente dela. Se
process.env.MEU_SECRETvoltaundefinede você tem certeza de que o secret existe, é quase sempre por isso. - Escopo mínimo nos tokens, e o tipo certo de token. Para novas integrações sistema a sistema, a HubSpot hoje aponta para as Service Keys (beta público) em vez dos apps privados legados: credenciais no nível da conta, criadas em Development > Keys, com escopos granulares como
crm.objects.contacts.read, enviadas como Bearer token e rotacionáveis com revogação imediata ou um período de carência opcional de 7 dias. Esse período de carência é exatamente o que você quer para o problema de rotação descrito abaixo. Os tokens de app privado legados continuam funcionando e não têm data de aposentadoria anunciada, então não há incêndio para apagar; mas, se você está criando a credencial hoje, crie uma Service Key e dê a ela só os escopos que aquela ação precisa. Vale notar que Service Keys não cobrem webhooks, UI extensions nem app pages; esses ainda exigem um app completo na plataforma de desenvolvedor. Se as suas chamadas começarem a falhar com 403 depois de uma mudança de escopo, nosso mergulho no erro de escopos da API da HubSpot percorre o diagnóstico, e os fundamentos estão no nosso guia de autenticação e apps na API da HubSpot.
Sobre rotação: ao atualizar o valor de um secret, espere uma pequena janela de propagação antes de as ações em execução pegarem o valor novo. Rotacione fora de janelas críticas de negócio e deixe o token antigo válido durante a virada; com uma Service Key da HubSpot isso é uma opção nativa (rotacionar com carência de 7 dias em vez de revogação imediata), e com qualquer outro provedor é uma disciplina manual que você mesmo precisa garantir.
Os limites que moldam a sua arquitetura
Os números que importam, direto da documentação de custom code da HubSpot:
- 20 segundos de tempo de execução. Limite rígido, sem extensão disponível. Esse orçamento inclui o cold start, todas as suas chamadas de API e a latência de rede delas.
- 128 MB de memória. Suficiente para lógica no nível do registro, não para carregar grandes volumes de dados na memória.
- Logs truncados por volta de 4 KB. Um
console.logde um objeto grande vai ser cortado exatamente onde você precisava ler. Logue de forma seletiva: IDs, códigos de status, pontos de decisão.
Esses limites não são arbitrários; eles estão dizendo para que a ferramenta serve. As consequências de arquitetura:
- Defina timeout explícito em toda chamada HTTP. O axios vem sem timeout por padrão, então uma API de terceiro lenta consome seu orçamento inteiro de 20 segundos e a ação morre sem um erro útil. Algo como
axios.get(url, { timeout: 5000 })transforma um timeout misterioso em uma falha capturável e logável. - Um registro, poucas chamadas. Se a lógica precisa de dados de muitos objetos, busque com os endpoints de batch (as leituras em lote da API de CRM existem para isso) em vez de fazer um loop de requisições individuais.
- Trabalho pesado vai para outro lugar. Sincronizações, atualizações em massa e jobs de vários minutos pertencem a um worker externo disparado por um webhook a partir do workflow, com os resultados escritos de volta no CRM. A custom code action é o despachante, não o motor.
Retries: o que a HubSpot faz por você, e o que ela espera de você

Esta é a parte menos compreendida das custom code actions, e a que causa incidentes de verdade em produção. O comportamento, segundo a documentação da HubSpot:
- Se o seu código lança um erro em um rate limit (429) ou em um erro de servidor (5xx), a HubSpot faz o retry da ação automaticamente, começando cerca de um minuto depois da falha e continuando com backoff exponencial por até três dias, com intervalos que se esticam até oito horas entre tentativas. O registro inscrito fica esperando naquela etapa até o retry ter sucesso ou a janela expirar. Isso importa para as expectativas: um registro que falha às 9h pode só ser tentado de novo no fim da tarde, então retries são uma rede de segurança, não um mecanismo de recuperação rápida.
- Qualquer outra exceção não tratada faz a ação falhar, e, dependendo das configurações do seu workflow, o registro ou para ali ou segue pelo fluxo sem nenhuma saída do seu código.
O que leva ao padrão em que a comunidade convergiu, e que é o que entregamos: lance o que deve ser retentado, capture o que não deve. Deixe os erros 429 e 5xx se propagarem para a maquinaria de retry da HubSpot fazer seu trabalho; capture as falhas de lógica de negócio (um 404 de um registro que não existe, um erro de validação) e trate-as explicitamente, logando e retornando um campo de saída de status sobre o qual seu workflow pode ramificar.
O corolário que morde os times: se a sua ação pode sofrer retry, ela precisa ser segura para rodar duas vezes. Um retry depois de uma falha parcial reexecuta a função inteira. Se o código já tinha criado uma fatura, enviado um e-mail ou incrementado um contador antes de morrer, o retry faz tudo de novo. Torne as ações idempotentes: verifique se o negócio já tem a fatura associada antes de criá-la, use IDs externos ou busque antes de criar, e desenhe as escritas de modo que rodar a mesma entrada duas vezes produza o mesmo resultado uma vez.
Uma dica de quem já se queimou: uma vez fomos chamados para depurar “faturas duplicadas aleatórias” que, no fim, eram um sistema de retry perfeitamente saudável fazendo seu trabalho sobre uma ação não idempotente. O código criava a fatura, dava timeout chamando um ERP lento e então lançava o erro; a HubSpot, obediente, fazia o retry e criava a fatura de novo. A correção não estava nas configurações de retry, estava em três linhas que buscavam antes uma fatura existente pelo ID do negócio. Escreva toda custom code action como se ela fosse rodar duas vezes, porque um dia ela vai.
Um checklist de produção para custom code actions
- Secrets criados e selecionados nesta ação, nunca hardcoded, com escopo mínimo (uma Service Key só com os escopos de que esta ação precisa, para integrações novas).
- Timeout explícito em toda chamada HTTP de saída, bem abaixo do orçamento de 20 segundos.
- Lançar erro em 429/5xx (deixar a HubSpot fazer o retry), capturar e ramificar nos erros de negócio.
- Escritas idempotentes: buscar antes de criar, IDs externos, nenhum efeito colateral incondicional.
- Logs limitados a IDs, códigos de status e decisões (lembre do truncamento em ~4 KB).
- Campos de saída para tudo o que as ações seguintes precisam, incluindo um status explícito.
- Jobs pesados despachados para workers externos, não espremidos nos 20 segundos.
- Testada com o recurso de teste do editor contra registros que atingem os casos extremos, não só o caminho feliz.
Perguntas frequentes
O que são custom code actions na HubSpot?
Ações de workflow que rodam o seu próprio código JavaScript (Node.js) ou Python para cada registro inscrito, permitindo implementar lógica que as ações nativas não alcançam: cálculos personalizados, chamadas a APIs externas, criação condicional de registros. Elas exigem o Data Hub Professional ou Enterprise (o hub antes conhecido como Operations Hub) e executam como funções serverless sem estado, com campos de saída definidos.
Quais são os limites das custom code actions da HubSpot?
A execução precisa terminar em 20 segundos usando no máximo 128 MB de memória, os logs truncam por volta de 4 KB e só as bibliotecas pré-carregadas (como o axios e o cliente oficial da HubSpot) estão disponíveis. Não há como estender esses limites; jobs mais longos devem rodar em sistemas externos disparados pelo workflow.
As custom code actions da HubSpot fazem retry automaticamente?
Sim, em um caso específico: quando o código lança erro em um rate limit (429) ou em um erro de servidor (5xx), a HubSpot refaz a ação automaticamente, começando cerca de um minuto depois da falha e continuando com backoff exponencial por até três dias, com intervalos de até oito horas entre tentativas. Outros erros não tratados fazem a ação falhar sem retry, então o padrão recomendado é lançar os erros retentáveis e capturar explicitamente todo o resto, além de tornar toda ação idempotente, já que um retry reexecuta a função inteira.
Como funcionam os secrets nas custom code actions?
Você cria os secrets no editor de custom code e os lê como variáveis de ambiente (process.env no Node, os.getenv no Python), com cada valor limitado a 1.000 caracteres. O detalhe crítico: cada ação tem sua própria lista de secrets selecionados, então um secret que existe no portal mas não foi adicionado àquela ação específica chega como undefined. Guarde tokens de API como secrets, nunca no próprio código, e, para integrações novas com a HubSpot, prefira uma Service Key com escopos mínimos a um token de app privado legado.
Custom code ou uma ferramenta de automação externa: quando usar cada um?
Use custom code para lógica cirúrgica no nível do registro, que caiba com folga em 20 segundos: scoring, formatação, uma consulta, uma escrita condicional. Use uma plataforma externa (n8n, funções serverless) quando o trabalho envolve volume, execução longa, múltiplos sistemas ou orquestração complexa, com o workflow disparando via webhook e os resultados escritos de volta no CRM.
Pronto para levar sua operação ao próximo nível.
Fale com um especialista e descubra como podemos ajudar.