| Projeto | Middleware de Integracao PetLove × HubSpot × Zenvia |
| Documento | Analise Tecnica — Health API, Enrollment API e Jornada do Site |
| Escopo | Dominio A — Jornada do Site (parte NAO-Zenvia do middleware) |
| Versao | 1.0 (baseado no Brief Tecnico v1.1) |
| Data | 05/03/2026 |
| Autor | Epic Digital — Equipe Tecnica |
| Referencia | Estimativa Tecnica V4.1 + Relatorio Tecnico Health API (25/02) |
Este documento apresenta a analise tecnica da integracao entre a Jornada do Site PetLove e o HubSpot CRM. O objetivo e permitir que, quando um cliente contrata um plano de saude pet pelo site, os dados relevantes sejam registrados automaticamente no HubSpot — incluindo contato, pet, negocio e eventos de timeline.
Para viabilizar essa integracao, foram mapeados dois caminhos possiveis, cada um com caracteristicas, vantagens e limitacoes distintas:
Fluxo A — Middleware: o site envia os dados para um servidor intermediario (Node.js) que processa, valida e grava no HubSpot. Toda a logica de negocio fica sob nosso controle, com versionamento via Git, deploy independente e sem limitacao de tempo de execucao.
Fluxo B — HubSpot Direto: o site envia os dados diretamente para o HubSpot via Forms ou API, e a logica e executada por Workflows com Custom Code. E uma solucao mais rapida de implementar, porem depende do plano Operations Hub Professional e possui limite de 20 segundos por execucao de codigo.
Ambos os fluxos entregam o mesmo resultado para o usuario final. A diferenca esta na arquitetura, nos prazos, nas dependencias de licenciamento e no nivel de controle sobre a operacao. As secoes a seguir detalham cada caminho, os endpoints disponiveis, os schemas de dados, os bloqueios identificados e as decisoes pendentes.
Este documento cobre o Dominio A — a Jornada do Site — em que o lead contrata um plano de saude pet pelo site da PetLove, e os dados sao gravados no HubSpot. O Brief Zenvia (v3.2) cobre o Dominio B separadamente.
Antes de apresentar os dois fluxos possiveis, um resumo do que e certo:
| O que | Status | Fonte |
|---|---|---|
| Health API funcionando emhttps://health-api.petlove.com.br | Confirmado | Testes exploratorios (25/02).Cloudflare + Laravel + Envoy. |
| 10 endpoints publicos testados e funcionais(species, races, regions, plans, campaign, etc.) | Confirmado | curl.exe com User-Agent.9 OK + 1 parcialmente ok (simulate). |
| 3 endpoints hook BLOQUEADOS(/api/hook/customer, plans, is-active-customer) | Sem token | 403/401 — aceita Bearer, X-Api-Key,x-hook-token, x-api-token. |
| Enrollment API: 6 endpoints documentados(customer, location, plans, simulate, proposal, status) | Host desconhecido | OpenAPI 3.1 documenta paths.Todos retornam 404 no host publico. |
| GET /api/plans aceita SOMENTE ID numerico(slugs retornam [] sem erro) | Pegadinha | Testes com 'sao-paulo' etc.Retorna 200 com array vazio. |
| GET /api/auth/find-account e publico(retorna nome, tipo conta, recovery methods) | Atencao | Endpoint publico que retornadados reais sem autenticacao. |
| Enrollment API tem campo seller.sourceSellerId(UUID do vendedor NO HUBSPOT) | Documentado | OpenAPI + Enrollment.md.Ponto-chave de rastreabilidade. |
| Proposal status mapeia direto para Deal stages(PENDING_PAYMENT, ACTIVE, CANCELED, etc.) | Documentado | Enrollment.md — 9 statuscorrespondem a stages do HubSpot. |
Neste fluxo, construimos um middleware (Node.js/Express) que fica entre o site da PetLove e o HubSpot. O site faz POST para o middleware, que processa tudo: cria objetos no HubSpot, chama a Enrollment API da PetLove, calcula MRR, dispara eventos. E o plano original da Estimativa V4.1.
O middleware e um servico Node.js/Express controlado por nos. Nao depende de nenhum recurso especial do HubSpot — precisa apenas da API padrao do CRM (qualquer plano com acesso a API).
PASSO 1 Lead entra no site PetLove e completa o WIZARD
(escolhe especie, raca, plano, preenche dados pessoais)
↓
PASSO 2 SITE faz POST /api/wizard para o Middleware
↓
PASSO 3 Middleware recebe e faz:
a) Cria Contact no HubSpot (upsert por email, sanitiza CPF)
b) Cria Pet (Custom Object: nome, especie, raca)
c) Cria Deal (negocio) + Line Items (plano + preco)
d) Cria Associations v4: Contact↔Deal, Pet↔Contact, Pet↔Deal
e) Dispara evento: lead_wizard_gerado
↓
PASSO 4 Lead confirma e vai para CHECKOUT
SITE faz POST /api/checkout para o Middleware
↓
PASSO 5 Middleware recebe e faz:
a) Chama Enrollment API → POST /proposal/simulate → precos reais
b) Atualiza Deal (stage, amount, MRR)
c) Chama Enrollment API → POST /proposal → cria proposta
d) Dispara evento: venda_concluida
↓
PASSO 6 Apos pagamento, lead preenche ATIVACAO
SITE faz POST /api/ativacao/dados-pet e POST /api/ativacao/microchip
↓
PASSO 7 Middleware recebe e faz:
a) Atualiza Pet com dados complementares e microchip
b) Atualiza Deal → stage: Ativo
c) Dispara evento: ativacao_concluida
↓
PASSO 8 HUBSPOT tem tudo: contato, pet, negocio, eventos, vendedor.
O lead completa o formulario do site: nome, email, telefone, CEP, especie, raca, plano desejado. O site envia tudo em um POST /api/wizard para o middleware. O middleware cria Contact (upsert por email), Pet (Custom Object), Deal (stage: Lead), Line Items (plano + preco), todas as Associations v4, e dispara o evento lead_wizard_gerado que aparece na timeline do contato.
O lead confirma o plano e vai para checkout. O site envia POST /api/checkout. O middleware chama a Enrollment API: primeiro /proposal/simulate para calcular precos reais (descontos, parcelas, addons), depois /proposal para submeter a proposta (com seller.sourceSellerId = ID do vendedor no HubSpot e source = 'Hubspot'). Atualiza Deal com amount, MRR e stage 'Proposta Enviada'. Dispara venda_concluida.
Apos pagamento, o lead preenche dados complementares do pet e define microchip. Dois sub-endpoints: POST /api/ativacao/dados-pet (atualiza Pet Custom Object) e POST /api/ativacao/microchip (atualiza Pet + muda Deal para 'Ativo'). Dispara eventos: ativacao_iniciada, microchip_escolhido, ativacao_concluida.
POST /api/wizard API CRM v3
_______________ POST /api/checkout _______________ _______________
| | POST /api/ativacao/*| | | |
| SITE PETLOVE | ==================>| MIDDLEWARE | | HUBSPOT |
| (frontend) | | (Node.js) |==> CRM |
|_______________| | | | |
| - Valida dados| | - Contact |
| - Upsert Cont.| | - Deal |
| - Create Pet |====> - Pet (CO) |
| - Create Deal | | - Line Items |
| - MRR calc | | - Events |
| - CPF sanit. | | - Assoc v4 |
| - Events disp.| | - Owner |
|_______________| |_______________|
||
______||______
| |
| ENROLLMENT |
| API PetLove |
| (host ?) |
|______________|
| Quem | Faz o que | Chama quem |
|---|---|---|
| Lead (visitante) | Preenche wizard, confirma checkout, completa ativacao no site | → Site PetLove (frontend) |
| Site PetLove(frontend) | Coleta dados e envia POST para o middleware (wizard, checkout, ativacao) | → Middleware (POST) |
| Middleware | Recebe POST, valida, cria objetos no HubSpot, chama Enrollment API (simulate, proposal), calcula MRR, sanitiza CPF, dispara eventos | → HubSpot (API CRM v3) → Enrollment API (POST) → Health API (GET) |
| HubSpot | Recebe dados via API e grava no CRM (Contact, Deal, Pet, Line Items, Events) | — (so recebe) |
| Enrollment API(PetLove backend) | Simula, cria proposta, retorna status + paymentLink | — (so responde) |
Neste fluxo, o site da PetLove envia dados diretamente para o HubSpot (via HubSpot Forms ou via API client-side/server-side). A logica de negocio (chamar a Enrollment API, calcular o MRR, criar associacoes) roda toda no Workflows com Custom Code. Nao ha middleware nem servico externo.
Tres capacidades do HubSpot permitem eliminar o middleware:
O site pode enviar dados do wizard diretamente para o HubSpot usando HubSpot Forms (embedded ou popup) ou a Forms Submit API (POST server-side). Quando o form e submetido, o HubSpot cria ou atualiza o Contact automaticamente e pode disparar um Workflow.
Dentro de um Workflow, e possivel rodar codigo Node.js ou Python como serverless function. O Custom Code pode chamar APIs externas (Enrollment API, Health API) e a API do HubSpot internamente.
| Limitacao | Valor |
|---|---|
| Timeout por execucao | 20 segundos (maximo) |
| Memoria | 128 MB |
| Plano necessario | Operations Hub Professional ou Enterprise |
| Bibliotecas Node.js disponiveis | @hubspot/api-client, axios, lodash, redis, aws-sdk, googleapis |
Alem do Custom Code, o Workflow oferece acoes nativas que substituem parte do que o middleware faria: criar Deal, criar associacao, definir propriedades, enviar notificacao, criar task.
PASSO 1 Lead entra no site PetLove e completa o WIZARD
(escolhe especie, raca, plano, preenche dados pessoais)
↓
PASSO 2 SITE submete um HubSpot Form (embed ou API submit)
→ HUBSPOT cria/atualiza o Contact automaticamente
↓
PASSO 3 WORKFLOW dispara (trigger: form submitted)
↓
PASSO 4 CUSTOM CODE #1 (Node.js) roda:
a) Le dados do Contact (especie, raca, plano, CEP)
b) Cria Pet (Custom Object) via @hubspot/api-client
c) Cria Deal + Line Items
d) Cria Associations v4
↓
PASSO 5 Lead confirma checkout (outro form submit ou webhook)
↓
PASSO 6 CUSTOM CODE #2 (Node.js) roda:
a) Chama Enrollment API: simulate → precos reais
b) Chama Enrollment API: proposal → cria proposta
c) Atualiza Deal (stage, amount, MRR)
↓
PASSO 7 Apos pagamento, lead preenche ativacao (outro form/webhook)
↓
PASSO 8 CUSTOM CODE #3 (Node.js) roda:
a) Atualiza Pet (dados complementares + microchip)
b) Atualiza Deal → stage: Ativo
↓
PASSO 9 HUBSPOT tem tudo: contato, pet, negocio, vendedor.
O site da PetLove usa um HubSpot Form (embedded ou via Submit API) em vez de chamar o middleware. O form coleta: nome, email, telefone, CEP, especie, raca, plano desejado. Ao submeter, o HubSpot cria/atualiza o Contact automaticamente. Um Workflow e triggered pelo form submit.
Dentro do Workflow, um bloco de Custom Code (Node.js) le os dados do Contact e usa @hubspot/api-client para criar: Pet (Custom Object), Deal (stage: Lead), Line Items (plano + preco), Associations v4 (Contact↔Deal, Pet↔Contact, Pet↔Deal). Tudo acontece dentro dos 20 segundos de timeout.
Quando o lead vai para checkout (outro submit ou webhook), um segundo Custom Code chama a Enrollment API via axios: POST /proposal/simulate (precos reais), depois POST /proposal (submete proposta). Atualiza o Deal com amount, MRR e stage. ATENCAO: simulate + proposal + update Deal precisam caber em 20 segundos.
Apos pagamento confirmado, o lead preenche ativacao. Um terceiro Custom Code atualiza Pet (dados complementares + microchip) e muda Deal para 'Ativo'.
HubSpot Form / Submit API
_______________ _________________________________
| | | HUBSPOT (Operations Hub) |
| SITE PETLOVE | =====================>| |
| (frontend) | | 1. Form submit → Create Contact |
|_______________| | 2. Workflow triggered |
| 3. Custom Code #1: |
| - @hubspot/api-client |
_______________ | - Pet, Deal, LI, Assoc v4 |
| ENROLLMENT | | 4. Custom Code #2 (checkout):|
| API PetLove | <==== axios =========| - Enrollment: simulate |
| (host ?) | | + proposal |
|______________| | - Update Deal (MRR,stage) |
| 5. Custom Code #3 (ativacao):|
_______________ | - Update Pet (microchip) |
| HEALTH API | | - Update Deal → Ativo |
| (publico) | <==== axios =========| |
|______________| | Resultado: Contact+Deal+Pet+LI |
|_________________________________|
| Quem | Faz o que | Chama quem |
|---|---|---|
| Lead (visitante) | Preenche wizard, confirma checkout, completa ativacao no site | → Site PetLove (frontend) |
| Site PetLove(frontend) | Submete HubSpot Forms (embed ou API) com dados do lead | → HubSpot (Form Submit) |
| HubSpotWorkflow + Custom Code | 1) Form submit cria Contact 2) Workflow triggera Custom Code 3) Custom Code cria Pet, Deal, LI, Assoc 4) Custom Code chama Enrollment API 5) Custom Code atualiza Deal stages |
→ Enrollment API (axios) → Health API (axios) → HubSpot (API interna) |
| Enrollment API(PetLove backend) | Simula, cria proposta, retorna status | — (so responde) |
| Criterio | Fluxo A — Site → Middleware → HubSpot | Fluxo B — Site → HubSpot (direto) |
|---|---|---|
| Precisa de Operations Hub? | NAO | SIM (Professional) |
| Precisa de servidor externo? | SIM (Node.js completo) | NAO (zero servidor) |
| Timeout? | Sem limite | 20 segundos por Custom Code |
| Memoria? | Sem limite | 128 MB |
| CPF Sanitization? | DataSanitizer dedicado(camada de middleware) | Manual no Custom Code(sem camada dedicada) |
| Server-side events (timeline)? | 6 eventos via Events API v3(sem impacto de timeout) | Possivel via Custom Code(consome parte dos 20s) |
| Chamada a Enrollment API? | Sem limite de tempoSimulate + Proposal em sequencia | Precisa caber em 20s(simulate + proposal + update) |
| Fila / DLQ / retry? | Fila propria (Bull, SQS)Dead Letter Queue dedicada | Retry do HubSpot (3 dias)Sem DLQ granular |
| Idempotencia? | Controle total (ID de req) | Implementar no Custom Code |
| Contact auto-create? | Middleware cria via API | HubSpot Forms cria nativo |
| Custom Object Pet? | Criado pelo middleware(schema controlado) | Criado pelo Custom Code(@hubspot/api-client) |
| Onde fica a logica? | Codigo (Git, testavel, CI/CD) | HubSpot UI (visual, sem Git) |
| Tempo de desenvolvimento | ~42 dias uteis (V4.1) | ~20-30 dias uteis (estimativa) |
| Complexidade de manutencao | Media (codigo versionado) | Baixa (HubSpot UI) |
| Risco com Enrollment lenta? | Baixo (sem timeout) | Alto (pode estourar 20s) |
DECISAO: A escolha depende de: (1) PetLove ja tem Operations Hub Professional? (2) A Enrollment API responde rapido o suficiente para caber em 20s? (3) A equipe prefere logica no HubSpot UI ou em codigo versionado? (4) O risco de CPF vazar sem DataSanitizer dedicado e aceitavel?
Independente do fluxo escolhido (A ou B), estes sao os endpoints PetLove que precisarao ser consumidos. Testados em 25/02/2026.
Host: https://health-api.petlove.com.br — Cloudflare + Laravel + Envoy. Requer User-Agent (ex: PostmanRuntime/7.36.0).
| # | Endpoint | Metodo | O que retorna | Status |
|---|---|---|---|---|
| 1 | GET /api/species | GET | Especies: Cachorro (1), Gato (2) | 200 |
| 2 | GET /api/races?specie={dog|cat} | GET | Racas por especie (~25 gato, ~200 cachorro) | 200 |
| 3 | GET /api/regions | GET | Regioes PetLove com IDs + coordenadas + plan_id | 200 |
| 4 | GET /api/location/states | GET | 27 estados brasileiros | 200 |
| 5 | GET /api/accredited-network/states | GET | 25 UFs com rede credenciada (faltam AP, RO) | 200 |
| 6 | GET /api/campaign | GET | Campanha ativa (imagens, datas, regulamento) | 200 |
| 7 | GET /api/plans?region={id} | GET | Planos por regiao (ID numerico!). Preco, cobertura, PDF. | 200 |
| 8 | GET /api/v1/partner_network/plans?lat=&long= | GET | Planos por geolocalizacao | 200 |
| 9 | GET /api/subscription/simulate | GET | Simulacao descontos (formato params desconhecido) | parcial |
| 10 | GET /api/auth/find-account?username= | GET | Verifica existencia de conta (nome, recovery) | 200 |
| # | Endpoint | Metodo | O que retorna (provavel) | Status |
|---|---|---|---|---|
| 1 | GET /api/hook/customer | GET | Dados do cliente via hook | 403/401 |
| 2 | GET /api/hook/plans | GET | Planos via hook | 403/401 |
| 3 | POST /api/hook/is-active-customer | POST | Verifica assinatura ativa | 401 |
| # | Endpoint | Metodo | O que faz | Status |
|---|---|---|---|---|
| 1 | /api/enrollment/v1/customer/{email} | GET | Cliente completo: dados, pets, assinaturas, microchip | 404 |
| 2 | /api/enrollment/v1/location/{postalCode} | GET | Localidade por CEP: UF, cidade, regiao | 404 |
| 3 | /api/enrollment/v1/plans/{region} | GET | Planos por regiao: nome, preco, produto, cupons | 404 |
| 4 | POST /api/enrollment/v1/proposal/simulate | POST | Simula proposta: descontos, parcelas, addons | 404 |
| 5 | POST /api/enrollment/v1/proposal | POST | Submete proposta (customer + pets + seller + source) | 404 |
| 6 | GET /api/enrollment/v1/proposal/{id} | GET | Status proposta + paymentLink | 404 |
Extraidos do Enrollment.openapi.json (15 schemas). Definem o mapeamento PetLove → HubSpot que precisara ser feito (tanto no Fluxo A quanto no B).
| Campo PetLove | Tipo | Mapeia para HubSpot |
|---|---|---|
| id | string (uuid) | — (interno) |
| string (email) | Contact → email (dedupe key) | |
| name | string | Contact → firstname |
| surname | string | Contact → lastname |
| birthDate | string (date) | Contact → date_of_birth |
| phones[] | Phone[] | Contact → phone |
| addresses[].city | string | Contact → city |
| addresses[].state | string | Contact → state |
| addresses[].postalCode | string | Contact → zip |
| addresses[].region.id | integer | Referencia para GET /plans |
| Campo PetLove | Tipo | Mapeia para HubSpot |
|---|---|---|
| name | string | Pet → nome_pet (primaryDisplay) |
| species | enum: cat/dog | Pet → especie |
| gender | enum: male/female | Pet → genero |
| birthDate | string (date) | Pet → data_nascimento |
| microchip.number | integer (ISO 11784) | Pet → microchip |
| subscription.status | enum (9 valores) | Deal → stage (mapeado) |
| subscription.plan | Plan object | Deal → amount + Line Items |
| Status Enrollment | Significado | Deal Stage HubSpot | Trigger |
|---|---|---|---|
| PENDING_PAYMENT | Aguardando pagamento | Proposta Enviada | Proposta criada |
| PENDING_CONTRACT | Pagamento ok, contrato pendente | Venda Concluida | Checkout aprovado |
| PENDING_CHIP | Aguardando microchip | Ativacao Pendente | Dados pet preenchidos |
| ACTIVE | Ativa | Ativo | Microchip definido |
| CANCELED | Cancelado | Cancelado | — |
| BLOCKED | Bloqueado | Bloqueado | — |
| SUSPENDED | Suspenso | Suspenso | — |
| Campo | Tipo | Relevancia para integracao |
|---|---|---|
| customer | Customer | Upsert Contact no HubSpot |
| proposalSubscriptions[] | { pet, plan, coupon } | Deal + Line Items + Pet |
| seller.sourceSellerId | string (uuid) | ID do vendedor NO HUBSPOT — rastreabilidade |
| source | string | 'Hubspot' — identifica origem da venda |
| submittedAt | string (date) | Deal → createdate |
| Propriedade | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
| nome_pet | string | Sim | primaryDisplayProperty |
| especie | enumeration | Sim | cachorro / gato |
| raca | string | Nao | Raca do pet |
| data_nascimento | date | Nao | Data de nascimento |
| genero | enumeration | Nao | male / female |
| microchip | string | Nao | Numero do microchip |
| status_pet | enumeration | Nao | Acompanha deal stage |
| De | Para | Tipo | Criado na fase |
|---|---|---|---|
| Contact | Deal | default + labeled | Wizard (Fase 1) |
| Pet | Contact | custom (discovery) | Wizard (Fase 1) |
| Pet | Deal | custom (discovery) | Wizard (Fase 1) |
| Line Item | Deal | default | Wizard (Fase 1) |
| Fase | Evento | Quando dispara |
|---|---|---|
| 1 — Wizard | pe{HubID}_lead_wizard_gerado | Lead completa o wizard |
| 2 — Checkout | pe{HubID}_tentativa_pagamento | Tentativa de pagamento |
| 2 — Checkout | pe{HubID}_venda_concluida | Checkout aprovado |
| 3 — Ativacao | pe{HubID}_ativacao_iniciada | Dados do pet preenchidos |
| 3 — Ativacao | pe{HubID}_microchip_escolhido | Microchip definido |
| 3 — Ativacao | pe{HubID}_ativacao_concluida | Ativacao concluida |
| ID | Item | Responsavel | Observacao |
|---|---|---|---|
| P1 | Evento de compra confirmada(server-side) | Health Track / Vindi | Direto do backend PetLove. NAO via middleware.Como o middleware/HubSpot e notificado? (GAP G4) |
| P2 | Enrollment API (hosting) | Backend PetLove | Middleware/HubSpot CONSOME; PetLove mantem.Host desconhecido. |
| P3 | Health API (hosting) | Backend PetLove | Fonte de referencia (especies, planos).Host: health-api.petlove.com.br |
| P4 | GTM → Google Analytics | Equipe dados PetLove | Sistema paralelo. Nao e HubSpot. |
| P5 | Migracao RD Station → HubSpot | Equipe dados PetLove | Carga legada. Deadline: 31/03. Nao e middleware. |
| # | Dependencia | Responsavel | Status | Impacto em ambos os fluxos |
|---|---|---|---|---|
| D1 | URL da Enrollment API(host real — nao e health-api) | Tech Lead PetLove | BLOQUEADO | A: bloqueia Fase 2 (checkout) B: bloqueia Custom Code #2 |
| D2 | Token para endpoints /api/hook/* | Tech Lead PetLove | BLOQUEADO | A: bloqueia hook/customer B: idem (se usar hooks) |
| D3 | Ambiente de staging PetLove | Tech Lead PetLove | BLOQUEADO | A + B: testes so contra prod (risco) |
| D4 | Definicao do evento de compra(como somos notificados?) | Tech Lead PetLove | BLOQUEADO | A: como middleware sabe? B: como HubSpot sabe? |
| # | GAP | Impacto | Decisao de |
|---|---|---|---|
| G4 | Como somos notificados quando o pagamento e confirmado? | ALTO — afeta checkout → ativacao | Tech Lead PetLove |
| G5 | Inside Sales — mesmo endpoint ou separado? | MEDIO — pode exigir rota extra | PetLove Comercial |
| G6 | /api/subscription/simulate — formato de params? | BAIXO — alternativa na Enrollment API | Tech Lead PetLove |