API da HubSpot: o guia completo para desenvolvedores (e para quem cansou de integração quebrada)
Deixa eu adivinhar como você chegou aqui. Alguém pediu para "puxar os contatos da HubSpot para o nosso sistema", você achou que seria uma tarde de trabalho, e três dias depois ainda está caçando por que a integração traz 9.900 registros e para. Ou pior: ela rodava, e numa madrugada qualquer começou a devolver um 429 que ninguém entende.
Se você se reconheceu, este guia é para você. A API da HubSpot é poderosa, mas ela tem regras próprias que não estão óbvias na primeira leitura da documentação. Quem aprende essas regras escreve integrações que rodam por meses sem ninguém tocar. Quem não aprende fica refazendo o mesmo script toda vez que a base cresce.
A boa notícia: as regras são poucas e fazem sentido quando você as vê juntas. Vou te mostrar todas elas, na ordem em que importam, com exemplos que você pode copiar. No fim, você vai saber ler, escrever, associar e automatizar na HubSpot sem cair nas armadilhas clássicas.
O que a API da HubSpot realmente resolve
A API da HubSpot serve para fazer programaticamente tudo o que você faria na interface, e em escala: ler e escrever dados do CRM, capturar leads de formulários, criar automações e conectar a HubSpot a ERPs, BIs e outras ferramentas. O portal vira uma peça do seu ecossistema, não uma ilha.
Na prática, três usos respondem pela maioria dos projetos. O primeiro é espelhar dados: levar contatos, empresas e negócios para um data warehouse ou banco, de onde um BI como o Power BI consome. O segundo é sincronizar sistemas: manter a HubSpot e um ERP falando a mesma língua. O terceiro é reagir a eventos: disparar um processo quando um negócio muda de estágio. Tudo o mais é variação desses três.
A base que todo mundo erra primeiro: autenticação
Toda chamada à API da HubSpot sai da mesma base, https://api.hubapi.com, e o portal afetado é definido pelo token, não pela URL. Isso tem uma consequência direta: o token é o item mais sensível de toda a operação. Quem segura o token, segura o portal.
1. App privado ou OAuth?
Existem dois caminhos de autenticação, e escolher o errado custa retrabalho. O app privado serve a um único portal, recebe um token fixo e é o caminho mais simples para integrações internas. O OAuth serve a apps que vários portais vão instalar, com fluxo de consentimento e tokens que se renovam. A regra é simples: um portal, app privado; muitos portais, OAuth.
2. Escopos: dê só o que a tarefa precisa
Cada token recebe escopos, que são permissões. Ler contatos exige crm.objects.contacts.read, escrever exige crm.objects.contacts.write, e assim por diante. O princípio é o do menor privilégio: um token de leitura não deve ter escopo de escrita. Isso reduz o estrago se o token vazar e facilita auditar quem fez o quê.
|
Authorization: Bearer <private_app_token> Content-Type: application/json |
|
Dica de quem já apanhou: se você recebe um erro 403 mesmo com o escopo habilitado, numa credencial estática as causas comuns são o escopo não ter sido salvo, ser o errado para o endpoint, ou você estar confundindo leitura com escrita. Adicionar o escopo e clicar em Salvar já aplica no token existente, sem regenerar. No OAuth, reinstale e reconsente. |
3. Guarde o token como segredo, sem exceção
O token nunca deve aparecer no corpo de uma coleção, em uma URL, em um log ou em um repositório de código. Guarde sempre em um cofre de credenciais: o Vault do Postman, o gerenciador do n8n ou do Make, ou variáveis de ambiente protegidas. Use um token por integração, para revogar um sem derrubar os outros, e gire os tokens periodicamente.
Ler dados sem perder registros
Leituras na HubSpot vêm em páginas, e a paginação é por cursor. A resposta traz um cursor em paging.next.after, e você repete a chamada passando esse valor até o cursor sumir. A regra de ouro, que resolve metade dos bugs de extração: na primeira chamada, não envie after. Alguns endpoints recusam um after vazio.
|
GET /crm/v3/objects/contacts?limit=100&properties=email,firstname // a resposta traz paging.next.after = "cursor123" GET /crm/v3/objects/contacts?limit=100&properties=email,firstname&after=cursor123 // repita até paging.next sumir |
Listagem, busca e batch não são a mesma coisa
Existem três formas de ler, e usar a errada é o que faz a integração parar em 9.900 registros. A tabela abaixo resume quando usar cada uma.
|
Forma |
Quando usar |
O limite que pega você |
|---|---|---|
|
Listagem (GET .../objects/{type}) |
Extração completa de um objeto |
100 por página, paginação por cursor |
|
Busca (POST .../search) |
Um recorte por data, estágio ou valor |
Teto de 10.000 por conjunto de filtros |
|
Batch read (POST .../batch/read) |
Você já tem os ids |
100 por lote, sem cursor |
Aquele caso clássico de parar em 10.000 é a Search API batendo no teto dela. A solução não é insistir, é quebrar a busca em faixas, por exemplo por janelas de data de criação, e paginar cada faixa separadamente. Cada faixa fica abaixo do teto e o conjunto cobre toda a base.
Sincronização incremental: só o que mudou
Da segunda execução em diante, você não quer trazer tudo de novo. Busque por hs_lastmodifieddate maior que o instante da última sincronização, com uma janela de sobreposição de alguns minutos para não perder registros alterados bem na virada do corte. A sobreposição traz alguns repetidos, que você remove deduplicando pelo id do registro. É melhor repetir e deduplicar do que perder uma atualização.
Escrever no CRM sem criar duplicata
Escrita na HubSpot é feita em lote, até 100 registros por requisição. E aqui mora a armadilha mais cara: a criação em lote não é idempotente. Rodar a mesma carga duas vezes cria duplicatas, e dados duplicados na HubSpot corroem a confiança nos relatórios e custam dinheiro. Por isso, coleções de escrita rodam uma vez, com o status conferido e o mapa de ids retornados guardado para conciliação.
|
POST /crm/v3/objects/contacts/batch/create { "inputs": [ { "properties": { "email": "ana@exemplo.com", "firstname": "Ana" } }, { "properties": { "email": "leo@exemplo.com", "firstname": "Leo" } } ] } |
A atualização em lote usa o id do registro, e os ids dentro de um mesmo lote precisam ser únicos. Se a mesma pessoa aparece duas vezes na lista de entrada, a API recusa o lote inteiro com erro de id duplicado. Deduplique por id antes de montar os lotes. E fique de olho no status 207, que indica sucesso parcial: parte do lote passou, parte falhou. Sempre leia o corpo da resposta para separar quem entrou de quem deu erro.
Associações: conectar os registros entre si
Um CRM não é uma lista de contatos solta, é uma teia. Associações conectam registros de objetos diferentes: um contato a uma empresa, uma atividade a um negócio. Além dos tipos padrão, você cria rótulos personalizados, como "Decisor" ou "Faturamento", para dar nome à relação. Na dúvida sobre qual id de tipo usar, consulte o endpoint de labels antes de associar em volume, porque os ids variam por par de objetos.
Automação: reagir a eventos com webhooks e workflows
Automatizar pela API vai além dos workflows visuais. Você cria fluxos pelo Automation v4, geralmente desligados, para revisar e ligar na interface depois. E você não fica preso ao critério por filtro: a API cria tanto os critérios que usam valor de propriedade e participação em lista quanto os critérios por evento, através de ramificações de filtro de evento com unified events, como inscrever um contato no envio de um formulário. Para reagir a mudanças em tempo real, use webhooks, tratando idempotência para não processar o mesmo evento duas vezes.
Onde a API te decepciona (e tudo bem)
Parte de dominar a API da HubSpot é saber o que ela não faz, para não perder um dia tentando. A tabela abaixo reúne os limites que mais surpreendem.
|
Área |
A limitação |
Como lidar |
|---|---|---|
|
Formulários |
Formulário novo não é criável por API, só o legacy |
Crie o formulário novo na interface |
|
Workflows |
Os payloads de inscrição são detalhados, e a API está em beta |
Crie critérios por filtro e por evento pela API, e revise antes de ligar |
|
Campos calculados |
Rollups são somente leitura |
Não tente gravar; derive via workflow |
|
Propriedades |
Não dá para mudar o tipo de uma propriedade existente |
Crie uma nova propriedade e migre os valores |
Limites de taxa: o 429 vai acontecer
Toda integração esbarra no erro 429 mais cedo ou mais tarde. Ele não é um defeito do seu código, é o controle de taxa da plataforma avisando que você passou do limite no período. O que separa uma integração frágil de uma robusta é a reação: respeitar o cabeçalho que diz quando tentar de novo e repetir com recuo progressivo.
|
Assinatura |
Limite diário |
Rajada |
|---|---|---|
|
Professional |
650.000 requisições por dia |
190 a cada 10 segundos |
|
Enterprise |
1.000.000 por dia |
190 a cada 10 segundos |
|
Apps mais antigos |
Menor, conforme o plano |
100 a cada 10 segundos |
A Search API tem um limite próprio e mais baixo que as leituras simples, então é nela que o 429 costuma aparecer primeiro. Reduza chamadas pedindo só as propriedades necessárias, use batch em vez de chamadas individuais, e limite a concorrência. Menos chamadas em paralelo significa menos 429 na origem.
Dá para fazer tudo isso sem programar
Um detalhe que pouca gente percebe: os mesmos endpoints podem ser operados por pessoas não técnicas em ferramentas visuais. A lógica é sempre a mesma, uma autenticação com o token, uma chamada a um endpoint e o tratamento da resposta página a página.
- Postman: organiza as chamadas em coleções. O Collection Runner executa as requisições em sequência e respeita o laço de paginação. Ótimo para extrações controladas e escritas que rodam uma vez.
- n8n: monta fluxos visuais ligando blocos, com um bloco nativo da HubSpot e um bloco HTTP para qualquer endpoint. A credencial fica no gerenciador, não no fluxo.
- Make: funciona por cenários, com módulos prontos da HubSpot e um módulo HTTP genérico, mais um iterator para percorrer cada página.
Na prática: o que muda quando a integração é bem feita
Deixa eu trazer dois cenários que vemos com frequência nas operações que assessoramos.
Cenário 1: o relatório que parava na metade
Uma operação extraía negócios para um painel e jurava que faltavam dados. A extração usava a Search API e parava sempre perto de 10.000 registros, batendo no teto sem ninguém perceber. Ao quebrar a busca em janelas de data de criação e paginar cada faixa, o painel passou a refletir a base inteira. O problema nunca foi o painel, era a forma de ler.
Cenário 2: a duplicata que nascia toda madrugada
Outra operação rodava uma carga de contatos todas as noites e a base inchava sem parar. A rotina usava criação em lote, que não é idempotente, sem checar se o contato já existia. Trocamos a lógica para buscar por email antes de criar e deduplicar por id, e o crescimento fantasma parou. A single source of truth começa por não duplicar na entrada.
|
Reflexão para quem lidera a operação: uma integração não é um projeto com data de fim, é um ativo que precisa de governança. Token no cofre, escopos mínimos, escrita reversível e monitoramento do 429. Esses quatro hábitos separam a integração que dorme tranquila da que acorda o time às três da manhã. |
Checklist: sua integração com a HubSpot está madura?
- O token está em um cofre de credenciais, com escopos mínimos e um token por integração?
- A leitura usa paginação por cursor, omitindo after na primeira chamada?
- As buscas grandes são quebradas em faixas para não bater no teto de 10.000?
- A sincronização é incremental, por data de modificação, com janela de sobreposição e deduplicação por id?
- A escrita roda uma vez, lê o status 207 e guarda o mapa de ids para conciliação?
- Existe tratamento de 429 com recuo progressivo e limite de concorrência?
Perguntas frequentes
Preciso saber programar para usar a API da HubSpot?
Não necessariamente. Os mesmos endpoints podem ser operados em ferramentas visuais como Postman, n8n e Make. A lógica é sempre a mesma: autenticar com o token, chamar o endpoint e tratar a resposta página a página.
Qual a diferença entre app privado e OAuth na HubSpot?
O app privado serve a um único portal e usa um token fixo, ideal para integrações internas. O OAuth serve a apps que vários portais vão instalar, com consentimento e tokens que se renovam. O alcance decide qual usar.
Por que minha extração para em 10.000 registros?
É o teto da Search API por conjunto de filtros. Não insista na mesma busca: quebre-a em faixas, por exemplo por janelas de data de criação, e pagine cada faixa separadamente para cobrir toda a base.
Por que recebo erro 403 mesmo com o escopo habilitado?
Em credencial estática (app privado ou service key), um escopo salvo passa a valer no token existente na hora, então confira se foi salvo no app certo, se é o escopo correto para o endpoint, e se você não está confundindo leitura com escrita. Regenerar não adiciona escopo. No OAuth, reinstale e reconsente.
A criação de registros em lote é segura para rodar duas vezes?
Não. A criação em lote não é idempotente: rodar duas vezes cria duplicatas. Rode coleções de escrita uma única vez, confira o status e, se precisar repetir, busque o registro antes de criar.
O que fazer quando a API responde 429?
Esperar e repetir com recuo progressivo, respeitando o cabeçalho que indica quando tentar de novo. Para prevenir, use batch, peça só as propriedades necessárias e limite a concorrência.
Quer tirar uma integração com a HubSpot do papel sem cair nessas armadilhas, ou arrumar uma que vive quebrando? Na Insight Sales, como parceiros HubSpot, construímos integrações com token no cofre, escrita reversível e monitoramento de verdade. Fale com a gente e descubra como podemos ajudar.
Pronto para levar sua operação ao próximo nível.
Fale com um especialista e descubra como podemos ajudar.