Forms API do HubSpot: captação de leads de qualquer site
Muita empresa convive com uma divisão silenciosa: o site foi feito por um time em uma stack, o CRM é o HubSpot, e o formulário da página de contato é um formulário HTML comum que posta no backend do próprio site. Alguém então escreve um cron que empurra essas submissões para o HubSpot uma vez por noite, e o time comercial não entende por que lead quente chega frio. O formulário funciona. O dado chega. Mas o lead perdeu o momento, o contexto da página e o cookie de rastreamento, e ninguém consegue dizer de qual campanha ele veio.
A Forms API existe para fechar essa divisão. Você mantém o seu formulário, o seu design e o seu front-end, e envia cada submissão para o HubSpot na hora em que ela acontece, com o contexto que o HubSpot precisa para atribuir a origem e com o registro de consentimento que a lei exige. Neste guia, percorro o caminho inteiro: quais formulários dá para criar via API, como mapear campos para propriedades antes de mexer em qualquer coisa, os dois endpoints de submissão e quando usar cada um, o bloco de consentimento, o cookie que faz a atribuição funcionar e os códigos de erro que você vai encontrar.
Quais formulários a API cria, e quais não cria
A Marketing Forms API v3 cria e gerencia formulários do tipo que o HubSpot chama de hubspot, o objeto de formulário clássico, com grupos de campos, opções de exibição e configurações de consentimento. São os formulários que você cria com POST /marketing/v3/forms/, lê com um GET no id do formulário e estende com um PATCH em fieldGroups. Eles funcionam com os endpoints de submissão descritos abaixo e com qualquer gatilho de workflow que leia um id de formulário.
O que a API não cria é formulário feito no editor novo do HubSpot. Se o seu time já usa esse editor, pode manter esses formulários nas páginas hospedadas no HubSpot, mas o formulário que recebe submissões de um site externo deve ser criado ou gerenciado pela API v3, para que o objeto onde você submete seja o mesmo que você define. Saber disso no começo evita a surpresa mais comum desse projeto: o time monta um formulário bonito no editor novo e depois descobre que a integração não consegue criar nem alterar aquele objeto por código.
Mapeie campos para propriedades antes de criar qualquer coisa
Todo campo de formulário grava em uma propriedade de contato, então o primeiro trabalho não é o formulário, é a auditoria de propriedades. Puxe todas as propriedades de contato com GET /crm/v3/properties/contacts?archived=false, que não é paginado, e para cada campo do site confira três coisas: já existe uma propriedade, pelo nome interno ou pelo rótulo; qual é o tipo e o tipo de campo; e os valores das opções batem exatamente com o que o site vai enviar.
Portais acumulam propriedades parecidas ao longo dos anos, várias variações do mesmo campo de cargo ou de porte da empresa. Reaproveite a que o site atual e os workflows ativos já usam, e só crie uma propriedade nova quando nada servir ou quando as faixas de opções forem incompatíveis, porque mudar uma faixa numérica em uma propriedade existente quebra os relatórios históricos. Antes de mexer em qualquer propriedade, liste os workflows ativos que dependem dela e do id atual do formulário, porque mudar opções, remover um campo ou trocar o site para um novo id de formulário quebra esses workflows sem nenhum aviso.
Quando precisar de uma propriedade de enumeração nova, crie com o rótulo igual ao valor em cada opção, a menos que o portal tenha outra convenção, e lembre que um PATCH em opções substitui a lista inteira. Leia sempre as opções atuais primeiro, faça o merge, envie a lista completa e confira o resultado. Um 409 na criação significa que a propriedade já existe, e isso pode ser tratado como sucesso.
Crie o formulário e desligue o reCAPTCHA
A criação é um único POST com o tipo do formulário, o nome, os grupos de campos, a configuração, as opções de exibição e as opções de consentimento. Deixe idempotente: liste os formulários existentes primeiro, com paginação por cursor, e pule a criação se já houver um com o mesmo nome. Duas configurações decidem se as submissões via API vão funcionar. recaptchaEnabled precisa ser false, porque um formulário com reCAPTCHA ligado rejeita toda submissão via API com FORM_HAS_RECAPTCHA_ENABLED. E cada objeto de campo precisa do tipo de objeto, do nome da propriedade, do tipo de campo do formulário e das flags de obrigatório e oculto.
Um detalhe vale mais do que parece: o valor de uma opção do formulário precisa existir na propriedade, mas o rótulo pode ser diferente. É o jeito limpo de mostrar um texto novo no site e continuar gravando o valor que os seus relatórios e workflows já conhecem. Você muda o que o visitante lê sem mudar o que o CRM armazena.
Dois endpoints de submissão, uma regra sobre a chave
As submissões vão para api.hsforms.com, e existem duas portas. O endpoint seguro, /submissions/v3/integration/secure/submit/{portalId}/{formGuid}, recebe uma credencial bearer; tanto uma chave de serviço da conta quanto um token de aplicativo privado com o escopo de forms funcionam. O endpoint público, /submissions/v3/integration/submit/{portalId}/{formGuid}, não recebe credencial nenhuma. A regra que decide entre os dois é de onde a chamada parte.
Se o site submete a partir de um backend, use o endpoint seguro e guarde a chave em uma variável de ambiente do servidor, nunca em código do navegador, nunca em variável de build exposta ao cliente, nunca no repositório. Se o site submete direto do navegador, não existe lugar seguro para uma chave, então use o endpoint público. O endpoint seguro também é o único que permite passar o IP do visitante, o que só faz sentido a partir de um servidor.
POST https://api.hsforms.com/submissions/v3/integration/secure/submit/{portalId}/{formGuid} Authorization: Bearer {key} { "submittedAt": 1718035200000, "fields": [ { "objectTypeId": "0-1", "name": "email", "value": "ana@example.com" }, { "objectTypeId": "0-1", "name": "firstname", "value": "Ana" } ], "context": { "hutk": "cookie_value", "pageUri": "https://site.com/contato", "pageName": "Contato" }, "legalConsentOptions": { "consent": { "consentToProcess": true, "text": "Concordo com o tratamento dos meus dados." } } }
O cookie que faz a atribuição funcionar
A diferença entre um lead que o HubSpot consegue atribuir e um que não consegue é o valor hutk dentro de context. É o cookie de rastreamento do HubSpot, gravado no navegador do visitante pelo código de tracking. Quando você passa esse valor junto com a submissão, o HubSpot liga o contato novo ao histórico de navegação que já registrou, e a origem, as páginas visitadas e a campanha ficam todas presas ao lead. Sem ele, o contato nasce limpo, sem histórico, e os seus relatórios de atribuição ficam com um buraco onde aquele lead deveria estar.
Em uma submissão pelo backend, leia o cookie no navegador, encaminhe para o servidor junto com os dados do formulário e coloque no contexto. Passe também a URI e o nome da página, para a submissão mostrar de onde veio. O timestamp vai em submittedAt, em milissegundos, e não pode ter mais de um mês.
Consentimento não é opcional, e nunca vem marcado
Pela LGPD e pelo GDPR, tratar os dados de alguém exige consentimento explícito, e o HubSpot faz valer isso na API. O formulário carrega uma configuração de consentimento, o site mostra uma caixa com o texto, e a submissão envia consentToProcess: true com o texto exibido somente quando o visitante marcou a caixa. A caixa nunca vem pré-marcada: o HubSpot não permite e a lei não aceita, então o site precisa bloquear o envio enquanto ela estiver vazia.
Uma submissão sem consentimento devolve um 400 com MISSING_PROCESSING_CONSENT, que é o teste negativo que vale manter na sua suíte. E se o texto de consentimento mudar um dia, mude nos três lugares de uma vez: no site, na configuração do formulário e no texto enviado em cada submissão. Divergência entre o que o visitante leu e o que foi registrado é exatamente o que uma auditoria procura.
Os códigos de erro que você vai encontrar
Uma tabela curta de respostas evita a maioria dos chamados de suporte. Um 200 significa que a submissão foi aceita. Um 400 significa não tente de novo; registre o errorType, porque ele diz exatamente qual é o problema: um campo que não está na definição do formulário devolve FIELD_NOT_IN_FORM_DEFINITION, que é o que acontece quando o site envia um campo honeypot ou qualquer campo que você não adicionou ao formulário. Um 401 ou 403 é problema de chave ou de escopo. Um 404 significa que o id do portal ou o guid do formulário está errado. Um 429 ou um 5xx é o único caso em que vale tentar de novo, com backoff exponencial, guardando o payload para nada se perder, a mesma disciplina de idempotência e dead-letter que mantém webhooks confiáveis. Registre o header x-hubspot-correlation-id em toda falha, porque é isso que o suporte do HubSpot vai pedir.
Duas regras de formatação eliminam uma classe inteira de 400. Valores de múltipla escolha vão em um único item de campo, separados por ponto e vírgula. E campos opcionais vazios devem ser omitidos, não enviados como string vazia.
Uma dica de quem já se queimou: teste três coisas antes de entregar a integração ao desenvolvedor: o endpoint seguro com a chave real, o endpoint público sem chave, e uma submissão sem consentimento, que precisa voltar como MISSING_PROCESSING_CONSENT. Use um e-mail de teste que seja seu, porque o teste cria ou atualiza um contato real. Dez minutos disso e o desenvolvedor recebe exemplos funcionando em vez de uma especificação para interpretar.
Por que isso importa para a sua operação
Um lead que chega ao HubSpot no segundo em que foi enviado, com origem e consentimento anexados, é um lead que vendas consegue trabalhar e marketing consegue medir. O mesmo lead chegando horas depois, sem contexto, é um nome em uma lista. A Forms API é o que transforma um site que não está hospedado no HubSpot em uma fonte de primeira linha de leads atribuídos e em conformidade, sem refazer o site.
O custo de pular a disciplina deste guia não é a integração falhar fazendo barulho. É ela funcionar mal em silêncio: duplicados por campos que não bateram, relatórios com vazios onde deveria haver atribuição e uma trilha de consentimento que não se sustenta. Cada passo daqui, a auditoria de propriedades, o endpoint certo, o cookie, o bloco de consentimento, é barato, e juntos eles são a diferença entre um formulário que alimenta o CRM e um que polui.
Na prática: os leads que chegavam toda manhã às seis
Uma empresa tinha o formulário do próprio site gravando no próprio banco e um job noturno que empurrava as linhas para o HubSpot. Todo lead chegava às seis da manhã com o mesmo horário de criação, sem origem, sem página, sem cookie. Vendas ligava para pessoas que tinham pedido contato na tarde anterior, e marketing não sabia dizer de qual campanha qualquer uma delas tinha vindo.
A correção foi manter o formulário e mudar para onde ele postava. O backend passou a enviar cada entrada ao endpoint seguro no momento em que chegava, com o cookie de rastreamento encaminhado do navegador, o contexto da página e o texto de consentimento que o visitante tinha aceitado. Os leads começaram a aparecer em tempo real, atribuídos à origem verdadeira, e a primeira ligação de follow-up saiu da manhã seguinte para dentro da primeira hora. O site não mudou. Só o último trecho mudou. Quando o follow-up em si precisa rodar dentro do HubSpot, o mesmo cuidado vale para ações de código personalizado e seus secrets.
Checklist para captação de leads com a Forms API
- Você auditou as propriedades de contato existentes e reaproveitou as que o site e os workflows já usam?
- O formulário foi criado pela API v3 com o reCAPTCHA desligado?
- O backend usa o endpoint seguro com a chave em variável de servidor, e o formulário só de navegador usa o endpoint público?
- Toda submissão carrega o cookie de rastreamento, a URI e o nome da página no contexto?
- O consentimento só é enviado quando o visitante marcou uma caixa que nunca vem pré-marcada, com o texto exato exibido?
- Você só tenta de novo em 429 e 5xx, registra o tipo de erro em 400 e guarda o correlation id?
Perguntas frequentes
Posso criar qualquer formulário do HubSpot pela API?
A Marketing Forms API v3 cria e gerencia formulários do tipo clássico hubspot. Formulários feitos no editor novo do HubSpot não são criados pela API, então o formulário que recebe submissões externas deve ser definido pela v3.
Qual endpoint de submissão devo usar?
O endpoint seguro quando o site submete a partir de um backend que consegue guardar a chave com segurança, e o endpoint público quando a submissão parte direto do navegador, onde nenhuma chave pode ser guardada com segurança.
Qual credencial o endpoint seguro aceita?
Uma credencial bearer: uma chave de serviço da conta ou um token de aplicativo privado com o escopo de forms. Guarde em variável de ambiente do servidor, nunca em código do cliente nem no repositório.
Por que meus leads estão sem a origem?
Porque a submissão não incluiu o cookie de rastreamento hutk no contexto. Encaminhe o cookie do navegador e envie junto com a submissão para o HubSpot ligar o contato ao histórico de navegação.
Por que a API rejeita minha submissão com MISSING_PROCESSING_CONSENT?
Porque o bloco de consentimento estava ausente ou falso. Envie consentToProcess: true com o texto de consentimento exibido somente depois que o visitante marcou uma caixa que nunca veio pré-marcada.
Quais erros devo tentar de novo?
Somente 429 e 5xx, com backoff exponencial e o payload guardado para reenvio. Um 400 aponta um problema definido no tipo de erro e deve ser registrado, não repetido.
Vamos conversar?
Quer que os leads do seu site caiam no HubSpot em tempo real, atribuídos e em conformidade, sem refazer o site? Na Insight Sales, desenhamos e entregamos integrações de formulários e sistemas de ponta a ponta. Fale com o nosso time 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.