/// 00 · pauta da reunião
Oito páginas no site. Dois Instant Forms na Meta. Seis POSTs no Worker.
Home, Saiba Mais e Sobre são o mesmo formulário de simulação. A Meta não passa pelo site: Instant Form de anúncio, outro cano até o HubSpot.
/// 01 · a lista da pauta
Oito URLs do site. Três delas são o mesmo POST.
Identificador RD é o path. No HubSpot vira GUID. Home, Saiba Mais e Sobre compartilham o GUID de simulação; o pageUri ainda separa a página.
01
SimulationForm id simular. Turnstile e consent. POST /api/rd/simulation-lead · RD home.
02
O mesmo form, compacto, formId=simular. Mesmo POST, mesmo RD home.
03
O mesmo form compacto, sem id no DOM. Mesmo POST, mesmo RD home.
04
Nome, e-mail, consent. Sem Turnstile. POST /api/rd/blog-lead · RD /blog.
05
Dois forms variant=generator na mesma página, âncora #form-gerador. POST /api/rd/generator-lead · kW, kWh, GDI/GDII, usina.
06
Form próprio. Turnstile. Sem checkbox de consent. POST /api/rd/contact-lead · UF nativo state.
07
Fatura + CEEE/RGE/CELESC/COPEL + 10 vendedores. E-mail opcional. POST /api/rd/calculator-lead.
08
Rota interna. GPS. RGE travada. Fila offline. POST /api/rd/pap-lead.
09
META consumidores
Instant Form · Facebook / Instagram
fora do Worker
Lead Ad pra quem assina energia. Espelha a simulação. Chega no HubSpot pelo Ads, original source Paid Social.
10
META geradores
Instant Form · Facebook / Instagram
fora do Worker
Lead Ad pra parceiro gerador. Espelha /seja-um-gerador. Segundo form ID, mesmo Pixel.
Fora da pauta, sem form. /faq, /sustentabilidade, /trabalhe-conosco (currículo por e-mail). A variante sustainability existe no model e não está em nenhuma página. Feira é a rota /calculadoraavant — a pasta calculadora-feira/ não está no disco.
Redes sociais
Instant Form da Meta é outro cano. O Pixel do site não captura lead de anúncio.
O site já dispara PageView no Pixel 1348712187476443 (adiado com GTM). Lead Ads de Facebook/Instagram nascem no Gerenciador de Anúncios e chegam no HubSpot pela integração Ads, sem passar pelo Worker.
Consumidores
Lead Ad · Instant FormAnúncio pra quem assina energia. Espelha a simulação: nome, empresa, CNPJ, WhatsApp, faixa de conta.
- Form mora no Ads Manager, não em avantenergia.com.br
- HubSpot: form mapping + original source Paid Social
- Perguntar o Instant Form ID e os campos atuais
Geradores
Lead Ad · Instant FormAnúncio pra parceiro gerador. Espelha /seja-um-gerador: kW, kWh, GDI/GDII, usina.
- Segundo Instant Form, segundo mapping
- Mesmo Pixel, outro form ID
- Quem é admin do Business Manager
| Pedir na sala | Pra quê |
|---|---|
| Admin no Business Manager e na ad account | Sem isso a Anne não conecta o HubSpot Ads. |
| Os dois Instant Forms já existem? IDs? | Se já rodam, só mapear campo a campo. Se não, criar no Ads Manager. |
| HubSpot Ads já ligado no Facebook? | Integração nativa. Matheus não escreve webhook. Anne (ou o admin do portal) clica em Marketing → Ads. |
| Campos de cada Instant Form | CNPJ, WhatsApp, kW — internal name tem que existir no contato, igual o site. |
| Quem paga o anúncio / quem aprova criativo | Fora do PR do site. Fica no comercial. |
O Worker não entra aqui. Lead Ads não POSTA em /api/rd/*. Pixel + fbclid no site só costuram sessão de quem já clicou e caiu na landing. Quem preenche o Instant Form dentro do Instagram nunca toca no React.
Fechar na reunião
Cinco decisões. Sem elas o PR espera.
| Pergunta | Padrão que eu faria |
|---|---|
| Home, Saiba Mais e Sobre: 1 GUID ou 3? | Um GUID simulação. Relatório por pageUri. Três forms só se o comercial quiser funil separado no HubSpot. |
| META: integração nativa HubSpot Ads ou Zapier? | Nativa. Menos peça. Precisa do portal + BM conectados. |
| E-mail na feira e no PaP? | Continua opcional com {fone}@sem-email.avantenergia.com.br, até a Anne mandar o contrário. |
| Dual-write RD + HubSpot? | Sim. 7–14 dias staging, 7 em prod. META pode ir direto pro HubSpot. |
| Histórico do RD e dos Lead Ads antigos? | CSV depois. O PR do site só o fluxo novo. |
/// 00 · Avant Energia · forms
O site já captura. O HubSpot ainda não recebe.
Oito URLs na pauta, seis Route Handlers no RD. A UI, o Turnstile e as máscaras BR ficam. Falta o portal da Anne, seis GUIDs e o cano dos Instant Forms da Meta.
O que você precisa
Dezesseis coisas. A Anne manda quinze. 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 do site continua no Worker. Instant Form da Meta entra pelo HubSpot Ads.
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.
13
Admin no Business ManagerVocê ou a Anne com admin no BM e na ad account. Sem isso o HubSpot Ads não conecta o Facebook.
14
Instant Form IDsDois forms nativos da Meta: consumidores e geradores. Se já rodam, manda o ID e os campos. Se não, cria no Ads Manager.
15
HubSpot Ads no FacebookMarketing → Ads no portal. Integração nativa. Matheus não escreve webhook. Lead Ads caem como Paid Social.
16
Campos dos Instant FormsCNPJ, WhatsApp, faixa de conta, kW, kWh — o internal name tem que existir no contato, igual o site. Mapping campo a campo.
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 no HubSpot eu preciso de vocês: SITE (8 URLs, 6 POSTs — home / como-funciona / sobre são o mesmo form) 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 — 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 META (Instant Forms nativos, fora do site) 8. admin no Business Manager + ad account 9. os dois Instant Forms — consumidores e geradores — IDs e campos 10. HubSpot Ads ligado no Facebook A cara dos forms do site fica igual. A gente só troca o destino do POST. Lead Ads não passam pelo Worker: caem no HubSpot pelo Ads. Decisões: home/saiba mais/sobre = 1 GUID ou 3? e-mail na calculadora vira obrigatório? importa o histórico do RD agora?
/// 01 · o que está no ar
Oito URLs na pauta. Seis bocas no Worker. Cada boca vira um GUID.
Home, Saiba Mais e Sobre postam em simulation-lead (RD home). Geradores, blog, contato, feira e PaP têm POST próprio. Instant Form da Meta não aparece nesta lista — é o trilho Ads.
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 feira
/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.
META consumidores
Instant Form · AdsFora do Worker. Lead Ad Facebook/Instagram. HubSpot Ads, original source Paid Social.
- Espelha a simulação: nome, empresa, CNPJ, WhatsApp, faixa
- Pixel
1348712187476443já no site (PageView) - Pedir Instant Form ID e campos na sala
META geradores
Instant Form · AdsSegundo Instant Form. Espelha /seja-um-gerador.
- kW, kWh, GDI/GDII, usina
- Mesmo Pixel, outro form ID
- Admin no Business Manager
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 GUIDs, propriedades, subscription type. Staging aponta pra sandbox se existir.
2
PR em developDual-write nos 6 POSTs. Tracking HubSpot entra. Script RD ainda no ar. Teste em staging.
3
META AdsBM + HubSpot Ads. Mapping dos dois Instant Forms. Pode ir ao vivo sem esperar o corte do RD.
4
Corte do site7 dias de dual-write. Merge main. Tira RD do Worker e o loader CloudFront. Refresh token RD revoga.
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
O PR do site são os seis POSTs. Instant Form da Meta é o portal Ads.
| Fica fora do Worker | Por quê |
|---|---|
| Instant Forms da Meta | Entram na reunião. Saiem pelo HubSpot Ads, não por /api/rd/*. |
| 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. |
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.