/// 00 · Avant Energia · forms
O site já captura. O HubSpot ainda não recebe.
Seis Route Handlers postam conversão no RD Station. A UI, o Turnstile e as máscaras BR ficam. O que falta é o portal da Anne e seis GUIDs.
O que você precisa
Doze coisas. A Anne manda onze. Uma você decide.
Sem isso o código não liga. Embed nativo do HubSpot não entra: perde a pele Avant, o Turnstile e as máscaras de CNPJ/WhatsApp. O POST continua no Worker, agora contra api.hsforms.com.
01
Convite no HubSpotUsuário com Super Admin, ou Marketing + Settings. Sem isso você não cria form, propriedade nem Private App.
02
Portal ID (Hub ID)O número do canto superior. Entra no tracking js.hs-scripts.com/{id}.js e no path do submit.
03
Private AppNome sugerido avant-energia-landing. Token vai de secret no Worker (prod + staging) e no GitHub Actions. Nunca no cliente.
04
Escopos do appforms, crm.objects.contacts.read/write, crm.schemas.contacts.read. Write no schema se você for criar as propriedades por API.
05
Seis forms (GUIDs)Simulação, gerador, blog, contato, calculadora, PaP. Um GUID cada. Marketing → Formulários. UUID na URL depois de /form/.
06
Propriedades de contatoAs cf_* do RD não existem no HubSpot. Sem propriedade com o internal name, o campo some em silêncio — o mesmo bug que já vimos no RD.
07
Tipo de inscrição (LGPD)subscriptionTypeId de e-mail/WhatsApp. Settings → Marketing → E-mail → Tipos de inscrição. Vai no legalConsentOptions.
08
Tracking no domínioConfirmar avantenergia.com.br e www no código de rastreamento. Cookie hubspotutk (hutk) costura sessão com o POST.
09
Mapa dos vendedoresAlex, Anne, Bruce, Guilherme, Marcelo, Mário, Milena, Rerison, Rômulo, Thyelli. Dropdown custom é mais barato que owner ID.
10
Sandbox ou portal de testeSe existir, o staging aponta pra ele. Se não, dual-write no portal real com um form “staging” separado.
11
Histórico do RDMigrar contato antigo é dump CSV, não form. Fora do PR do site. Pergunta: entra agora, depois, ou fica no RD morto?
12
E-mail na calculadoraHoje é opcional: o Worker inventa {fone}@sem-email.avantenergia.com.br porque o RD exige e-mail. HubSpot também. Anne decide se vira obrigatório.
Três decisões de produto
Isso muda o desenho do form no HubSpot.
| Pergunta | Padrão que eu faria | Por quê |
|---|---|---|
| Embed do HubSpot ou API? | API no Worker. UI Avant. | Turnstile, máscara, calculadora e PaP GPS não cabem no embed. |
| Vendedor = owner do HubSpot? | Propriedade dropdown vendedor. |
Owner ID muda quando alguém sai. O select do site já tem os 10 nomes. |
| Criar empresa (company) junto? | Só contato, com company texto. |
É o que o RD faz hoje. Company object é um segundo PR. |
| Dual-write RD + HubSpot? | Sim, 7–14 dias no staging e 7 em prod. | Se o GUID estiver errado, o comercial não fica cego. |
Fica. Turnstile, GTM GTM-P4NFJGD6, Meta Pixel, máscaras BR, fila offline do PaP, noindex do staging. O script RD d335luupugsy2.cloudfront.net/…fe3514da-…-loader.js sai no cutover, não no dual-write.
Rascunho · não enviado
Zap pra Anne, se você quiser mandar.
Copia, ajusta o tom, manda você. Eu não envio daqui.
Anne, pra ligar os forms do site no HubSpot eu preciso de vocês: 1. me convidar no portal (super admin ou marketing + settings) 2. o Portal ID 3. uma Private App “avant-energia-landing” (ou me deixa criar) com escopo forms + contacts 4. 6 formulários criados — simulação, gerador, blog, contato, calculadora, pap — e o GUID de cada um 5. as propriedades custom (CNPJ, vendedor, concessionária, valor da conta, desconto, GPS do pap) 6. o tipo de inscrição de comunicação (LGPD) 7. confirmar o tracking em avantenergia.com.br A cara dos forms do site fica igual. A gente só troca o destino do POST. Duas decisões: o e-mail na calculadora vira obrigatório? e a gente importa o histórico do RD agora ou só o fluxo novo?
/// 01 · o que está no ar
O site já tem seis bocas. Cada uma vira um form HubSpot.
Hoje o identificador de conversão do RD é path (home, /contato/, /calculadoraavant/). No HubSpot o equivalente é o GUID do form. A origem continua no campo origem.
Simulação
home · /como-funciona · /sobrePOST /api/rd/simulation-lead → GUID simulação. Turnstile sim. Consentimento sim.
- Obrigatório: nome, empresa, CNPJ 14, e-mail, WhatsApp, consent
- Opcional: cidade, faixa de consumo
- Variante sustentabilidade: sem CNPJ; exige cidade + faixa
- RD:
cf_cnpj,cf_qual_sua_media_de_consumo,legal_bases
Faixas: Até 1.000 · 1.000–2.000 · 2.000–3.500 · Acima de 3.500.
Gerador
/seja-um-gerador/POST /api/rd/generator-lead → GUID gerador. Turnstile sim.
- Obrigatório: nome, WhatsApp, e-mail, kW, kWh/mês, GDI/GDII, usina sim/não, consent
- Opcional: observações, informações adicionais
- RD:
cf_potencia_instalada_kw,cf_geracao_media_mensal_kwh,cf_modalidade,cf_usina_em_operacao
O GH Actions hoje não injeta o identifier do gerador — o código cai no fallback do path.
Blog
/blogPOST /api/rd/blog-lead → GUID blog. Turnstile não.
- Obrigatório: nome, e-mail, consent
- RD:
available_for_mailing,cf_aceito_receber_comunicacoes
Único form público sem Turnstile. No HubSpot dá pra manter assim, mas o Worker continua aberto a bot. Vale colocar o widget no mesmo PR.
Contato
/contato/POST /api/rd/contact-lead → GUID contato. Turnstile sim. Sem checkbox de consent.
- Obrigatório: nome, e-mail, cidade, UF, empresa, mensagem (≥10), WhatsApp
- RD:
cf_mensagem(e o legadomensagem)
UF é select de 27 códigos. HubSpot state nativo aguenta.
Calculadora
/calculadoraavant/POST /api/rd/calculator-lead → GUID calculadora. Turnstile sim.
- Obrigatório: nome, WhatsApp, consultor, fatura ≥1, concessionária, solicitar fatura
- Opcional: e-mail, empresa, cidade, CNPJ, notas, red flag
- Calculado: modalidade, % desconto, economia mensal
- Concessionárias: CEEE, RGE, CELESC, COPEL
Sem e-mail o Worker fabrica {digits}@sem-email.avantenergia.com.br. O RD já recusou payload sem e-mail.
PaP
/calculadorapap/ · noindexPOST /api/rd/pap-lead → GUID pap. Turnstile sim. Fila offline se 5xx/rede.
- Obrigatório: nome do contato, empresa, WhatsApp
- Opcional: CNPJ, vendedor, notas, fatura
- GPS: lat, lng, precisão, status capturada/indisponível
- Utility travada em RGE
Rota interna. O workflow de Cloudflare também não manda o identifier PAP — fallback no código.
Propriedades HubSpot
Internal name tem que existir antes do primeiro POST.
No RD, campo desconhecido some quieto. No HubSpot Forms API é a mesma coisa: o submit 200 e o valor não grava. Cria a propriedade, coloca no form, aí o Worker manda.
| Internal name | Tipo | De onde vem |
|---|---|---|
email firstname phone mobilephone company city state | Nativos | Todos os forms. Nome inteiro vai em firstname. |
cnpj | texto, 14 dígitos | simulação, calculadora, pap |
whatsapp | texto | espelho do phone, calculadora/pap |
vendedor | dropdown 10 nomes | calculadora, pap |
distribuidora | dropdown CEEE/RGE/CELESC/COPEL | calculadora, pap |
consumo / valor_gasto_medio | número ou texto | calculadora (R$) e simulação (faixa) |
percentual_de_desconto economia_mensal modalidade | texto | projeção da calculadora/pap |
solicitar_fatura | dropdown | calculadora |
potencia_instalada_kw geracao_media_mensal_kwh usina_em_operacao | número / sim-não | gerador |
mensagem observacoes informacoes_adicionais | textarea | contato, gerador, calculadora, pap |
origem url_de_conversao | texto | calculadoraavant, calculadora-pap, page_url |
latitude longitude precisao_gps geolocalizacao_status | texto/número | pap |
aceito_receber_comunicacoes | sim/não + legalConsent | simulação, gerador, blog |
Não usa. Non-HubSpot form capture. O POST é JSON React, não HTML nativo — o HubSpot não vê. Também não usa o embed JS. Também não manda UTM no payload se o hutk estiver no ar: o tracking code já pega utm_*, gclid, fbclid. O Worker ainda pode mandar os nativos hs_google_click_id / hs_facebook_click_id como cinto.
/// 02 · o que muda no repo
O POST continua no Worker. Troca o destinatário.
Endpoint público do cliente pode até ficar /api/rd/… no dual-write e virar /api/hubspot/… no corte. O browser não fala com o HubSpot. O token não vaza.
| Hoje | Vira |
|---|---|
src/lib/rd-station.ts refresh + api.rd.services/platform/events |
src/lib/hubspotForms.ts POST https://api.hsforms.com/submissions/v3/integration/secure/submit/{portalId}/{formGuid} com Bearer do Private App |
src/lib/rdTracking.ts cookies rdtrk / __trf_src |
lê hubspotutk → context.hutk. IP de cf-connecting-ip → context.ipAddress. pageUri / pageName do body. |
layout.tsx loader RD CloudFront |
https://js.hs-scripts.com/{HUBSPOT_PORTAL_ID}.js no mesmo defer idle do GTM/Pixel. Portal ID é público. |
src/app/api/rd/*/route.ts (6) |
mesmo contrato de entrada (Turnstile + validação). Dual-write chama RD e HubSpot. Corte só HubSpot. |
payloads em calculatorLeadModel, papLeadModel, generatorLead |
fields: [{objectTypeId:"0-1", name, value}]. Valor sempre string. Sem campo vazio. |
Secrets
Três lugares: Worker, Worker staging, GitHub Actions.
O workflow já injeta RD_STATION_* e os NEXT_PUBLIC_RD_*_ENDPOINT. Gerador e PaP identifiers não estão no YAML — só fallback no código. No HubSpot cada form precisa do GUID no secret, senão o PR nasce coxo igual.
HUBSPOT_PORTAL_ID— público, pode ser varHUBSPOT_PRIVATE_APP_TOKEN— secret Worker prod + stagingHUBSPOT_FORM_GUID_SIMULATIONHUBSPOT_FORM_GUID_GENERATORHUBSPOT_FORM_GUID_BLOGHUBSPOT_FORM_GUID_CONTACTHUBSPOT_FORM_GUID_CALCULATORHUBSPOT_FORM_GUID_PAPHUBSPOT_SUBSCRIPTION_TYPE_ID— consentimento- Turnstile, GTM, Pixel — iguais
Testes. Os models já têm Vitest + payload RD. O PR ganha o espelho HubSpot: campo vazio some, CNPJ só dígito, e-mail fake da calculadora, hutk ausente ainda 200, Turnstile 400. Comando único: npm run check no landing-page-next-cloudflare.
/// 03 · cutover
Anne libera o portal. Você liga o POST. O comercial confere um lead.
1
PortalConvite, Private App, 6 forms, propriedades, subscription type. Staging aponta pra sandbox se existir.
2
PR em developDual-write. Tracking HubSpot entra. Script RD ainda no ar. Teste nos 6 POSTs em staging.
3
7 diasLead de verdade na calculadora e no home. Anne abre o contato no HubSpot e bate campo a campo.
4
CorteMerge main. Tira RD do Worker e o loader CloudFront. Refresh token RD revoga. Histórico CSV se ela pediu.
Critério de pronto
Um submit de cada form aparece no HubSpot com hutk, UTM se a URL tinha, CNPJ só número, vendedor da lista, e o Turnstile continua barrando POST sem token.
Fora deste PR
Forms do site. Só isso.
| Fica fora | Por quê |
|---|---|
| Ploomes, Exact, RD CRM legado | O dossiê da Anne (15/10) já mandou esses pra fora. HubSpot é o destino. |
| WhatsApp Meta / Tyxter | Outro fio. Form grava contato; zap comercial é o CRM deles. |
| Deal automático | Hoje o RD só cria conversão/contato. Deal é workflow no HubSpot, não no Worker. |
| Importação em massa do RD | CSV / ferramenta nativa. Não passa pelo form. |
| calculadora-feira | Pasta sumiu do disco. PaP vive em /calculadorapap no Next. |
Risco conhecido. Calculadora e PaP sem e-mail real. Se a Anne recusar o domínio sem-email.avantenergia.com.br, o form da calculadora ganha e-mail obrigatório — mudança de UX, não só de API.