DEV Community

Cover image for Como Usar a API do HubSpot em 2026
Lucas
Lucas

Posted on • Originally published at apidog.com

Como Usar a API do HubSpot em 2026

Resumo

API do HubSpot permite integrações diretas com hubs de CRM, marketing, vendas e serviços via OAuth 2.0 ou aplicativos privados, com endpoints RESTful para contatos, empresas, negócios (deals), tickets e muito mais. Os limites de taxa variam conforme a assinatura. Veja como configurar autenticação, acessar endpoints essenciais, trabalhar com webhooks e preparar sua integração para produção.

Experimente o Apidog hoje mesmo

Introdução

O HubSpot gerencia mais de 194.000 contas de clientes e bilhões de registros de CRM. Se você desenvolve integrações para CRM, automação de marketing ou vendas, conectar-se à API do HubSpot é essencial para atingir milhões de usuários.

Automatize tarefas repetitivas: empresas perdem de 15 a 20 horas por semana com digitação manual entre sistemas. Uma integração robusta com a API do HubSpot automatiza sincronização de contatos, atualizações de negócios, workflows de marketing e relatórios, eliminando trabalho manual.

💡 Dica: O Apidog facilita o teste de integrações com a API: valide endpoints do HubSpot, fluxos OAuth, webhooks e problemas de autenticação em um só lugar. Importe specs, simule respostas e compartilhe cenários de teste.

O Que É a API do HubSpot?

A API do HubSpot é RESTful e oferece acesso a dados de CRM e automação de marketing:

  • Contatos, empresas, negócios, tickets, objetos customizados
  • E-mails de marketing, landing pages
  • Pipelines de vendas, sequências
  • Tickets de suporte, conversas
  • Relatórios, analytics
  • Automação e workflows
  • Gestão de arquivos e ativos

Principais Recursos

Recurso Descrição
Design RESTful Métodos HTTP padrão com respostas JSON
OAuth 2.0 + Aplicativos Privados Opções de autenticação flexíveis
Webhooks Notificações em tempo real para alterações de objetos
Limitação de Taxas Limites baseados em níveis (100-400 requisições/segundo)
Objetos CRM Suporte para objetos padrão e personalizados
Associações Conecta objetos (contato-empresa, negócio-contato)
Propriedades Campos personalizados para qualquer tipo de objeto
API de Pesquisa Filtragem e ordenação complexas

Visão Geral da Arquitetura da API

A base é:

https://api.hubapi.com/
Enter fullscreen mode Exit fullscreen mode

Versões da API Comparadas

Versão Status Autenticação Caso de Uso
CRM API v3 Atual OAuth 2.0, Aplicativo Privado Todas as novas integrações
Automation API v4 Atual OAuth 2.0, Aplicativo Privado Inscrição em fluxos de trabalho
Marketing Email API Atual OAuth 2.0, Aplicativo Privado Campanhas de e-mail
Contacts API v1 Obsoleta Chave de API (legado) Migrar para v3
Companies API v1 Obsoleta Chave de API (legado) Migrar para v3

Importante: Chaves de API foram descontinuadas. Migre para OAuth 2.0 ou aplicativos privados.

Primeiros Passos: Configuração da Autenticação

Passo 1: Crie Sua Conta de Desenvolvedor HubSpot

  1. Acesse o Portal do Desenvolvedor HubSpot
  2. Faça login ou crie uma conta HubSpot
  3. Vá até Aplicativos no painel do desenvolvedor
  4. Clique em Criar aplicativo

Passo 2: Escolha o Método de Autenticação

Método Melhor Para Nível de Segurança
OAuth 2.0 Aplicativos multi-tenant, integrações públicas Alto (tokens com escopo de usuário)
Aplicativo Privado Integrações internas, portal único Alto (token com escopo de portal)

Passo 3: Configurar Aplicativo Privado (Recomendado para Integrações Internas)

  1. Acesse Configurações > Integrações > Aplicativos Privados
  2. Clique em Criar um aplicativo privado
  3. Defina os escopos necessários:
contacts
crm.objects.companies
crm.objects.deals
crm.objects.tickets
automation
webhooks
Enter fullscreen mode Exit fullscreen mode
  1. Gere o token de acesso
  2. Salve em um local seguro
# .env
HUBSPOT_ACCESS_TOKEN="pat-na1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
HUBSPOT_PORTAL_ID="12345678"
Enter fullscreen mode Exit fullscreen mode

Passo 4: Configurar OAuth 2.0 (Para Multi-Tenant)

const HUBSPOT_CLIENT_ID = process.env.HUBSPOT_CLIENT_ID;
const HUBSPOT_CLIENT_SECRET = process.env.HUBSPOT_CLIENT_SECRET;
const HUBSPOT_REDIRECT_URI = process.env.HUBSPOT_REDIRECT_URI;

// URL de autorização OAuth
const getAuthUrl = (state) => {
  const params = new URLSearchParams({
    client_id: HUBSPOT_CLIENT_ID,
    redirect_uri: HUBSPOT_REDIRECT_URI,
    scope: 'crm.objects.contacts.read crm.objects.contacts.write',
    state: state,
    optional_scope: 'crm.objects.deals.read'
  });

  return `https://app.hubspot.com/oauth/authorize?${params.toString()}`;
};
Enter fullscreen mode Exit fullscreen mode

Passo 5: Trocar Código por Token de Acesso

const exchangeCodeForToken = async (code) => {
  const response = await fetch('https://api.hubapi.com/oauth/v1/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: HUBSPOT_CLIENT_ID,
      client_secret: HUBSPOT_CLIENT_SECRET,
      redirect_uri: HUBSPOT_REDIRECT_URI,
      code: code
    })
  });

  const data = await response.json();

  return {
    accessToken: data.access_token,
    refreshToken: data.refresh_token,
    expiresIn: data.expires_in,
    portalId: data.hub_portal_id
  };
};

// Callback OAuth
app.get('/oauth/callback', async (req, res) => {
  const { code, state } = req.query;

  try {
    const tokens = await exchangeCodeForToken(code);

    // Armazene tokens no BD
    await db.installations.create({
      portalId: tokens.portalId,
      accessToken: tokens.accessToken,
      refreshToken: tokens.refreshToken,
      tokenExpiry: Date.now() + (tokens.expiresIn * 1000)
    });

    res.redirect('/success');
  } catch (error) {
    console.error('OAuth error:', error);
    res.status(500).send('Authentication failed');
  }
});
Enter fullscreen mode Exit fullscreen mode

Passo 6: Atualizar Token de Acesso

const refreshAccessToken = async (refreshToken) => {
  const response = await fetch('https://api.hubapi.com/oauth/v1/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      client_id: HUBSPOT_CLIENT_ID,
      client_secret: HUBSPOT_CLIENT_SECRET,
      redirect_uri: HUBSPOT_REDIRECT_URI,
      refresh_token: refreshToken
    })
  });

  const data = await response.json();

  return {
    accessToken: data.access_token,
    refreshToken: data.refresh_token,
    expiresIn: data.expires_in
  };
};

// Middleware para garantir token válido
const ensureValidToken = async (portalId) => {
  const installation = await db.installations.findByPortalId(portalId);

  if (installation.tokenExpiry < Date.now() + 1800000) {
    const newTokens = await refreshAccessToken(installation.refreshToken);

    await db.installations.update(installation.id, {
      accessToken: newTokens.accessToken,
      refreshToken: newTokens.refreshToken,
      tokenExpiry: Date.now() + (newTokens.expiresIn * 1000)
    });

    return newTokens.accessToken;
  }

  return installation.accessToken;
};
Enter fullscreen mode Exit fullscreen mode

Passo 7: Fazer Chamadas de API Autenticadas

const HUBSPOT_BASE_URL = 'https://api.hubapi.com';

const hubspotRequest = async (endpoint, options = {}, portalId = null) => {
  const accessToken = portalId ? await ensureValidToken(portalId) : process.env.HUBSPOT_ACCESS_TOKEN;

  const response = await fetch(`${HUBSPOT_BASE_URL}${endpoint}`, {
    ...options,
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
      ...options.headers
    }
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`HubSpot API Error: ${error.message}`);
  }

  return response.json();
};

// Exemplo de uso
const contacts = await hubspotRequest('/crm/v3/objects/contacts');
Enter fullscreen mode Exit fullscreen mode

Trabalhando com Objetos CRM

Criando um Contato

const createContact = async (contactData) => {
  const contact = {
    properties: {
      email: contactData.email,
      firstname: contactData.firstName,
      lastname: contactData.lastName,
      phone: contactData.phone,
      company: contactData.company,
      website: contactData.website,
      lifecyclestage: contactData.lifecycleStage || 'lead'
    }
  };

  const response = await hubspotRequest('/crm/v3/objects/contacts', {
    method: 'POST',
    body: JSON.stringify(contact)
  });

  return response;
};

// Uso
const contact = await createContact({
  email: 'john.doe@example.com',
  firstName: 'John',
  lastName: 'Doe',
  phone: '+1-555-0123',
  company: 'Acme Corp',
  lifecycleStage: 'customer'
});

console.log(`Contact created: ${contact.id}`);
Enter fullscreen mode Exit fullscreen mode

Propriedades do Contato

Propriedade Tipo Descrição
email String E-mail principal (identificador único)
firstname String Primeiro nome
lastname String Sobrenome
phone String Número de telefone
company String Nome da empresa
website String URL do site
lifecyclestage Enum lead, marketingqualifiedlead, salesqualifiedlead, opportunity, customer, evangelist, subscriber
createdate DateTime Gerado automaticamente
lastmodifieddate DateTime Gerado automaticamente

Obtendo um Contato

const getContact = async (contactId) => {
  const response = await hubspotRequest(`/crm/v3/objects/contacts/${contactId}`);
  return response;
};

// Uso
const contact = await getContact('12345');
console.log(`${contact.properties.firstname} ${contact.properties.lastname}`);
console.log(`Email: ${contact.properties.email}`);
Enter fullscreen mode Exit fullscreen mode

Pesquisando Contatos

const searchContacts = async (searchCriteria) => {
  const response = await hubspotRequest('/crm/v3/objects/contacts/search', {
    method: 'POST',
    body: JSON.stringify({
      filterGroups: searchCriteria,
      properties: ['firstname', 'lastname', 'email', 'company'],
      limit: 100
    })
  });

  return response;
};

// Exemplo: buscar contatos de uma empresa
const results = await searchContacts({
  filterGroups: [
    {
      filters: [
        {
          propertyName: 'company',
          operator: 'EQ',
          value: 'Acme Corp'
        }
      ]
    }
  ]
});

results.results.forEach(contact => {
  console.log(`${contact.properties.email}`);
});
Enter fullscreen mode Exit fullscreen mode

Operadores de Filtro de Pesquisa

Operador Descrição Exemplo
EQ Igual a company EQ 'Acme'
NEQ Diferente de lifecyclestage NEQ 'subscriber'
CONTAINS_TOKEN Contém email CONTAINS_TOKEN 'gmail'
NOT_CONTAINS_TOKEN Não contém email NOT_CONTAINS_TOKEN 'test'
GT Maior que createdate GT '2026-01-01'
LT Menor que createdate LT '2026-12-31'
GTE Maior ou igual a deal_amount GTE 10000
LTE Menor ou igual a deal_amount LTE 50000
HAS_PROPERTY Possui valor phone HAS_PROPERTY
NOT_HAS_PROPERTY Valor ausente phone NOT_HAS_PROPERTY

Criando uma Empresa

const createCompany = async (companyData) => {
  const company = {
    properties: {
      name: companyData.name,
      domain: companyData.domain,
      industry: companyData.industry,
      numberofemployees: companyData.employees,
      annualrevenue: companyData.revenue,
      city: companyData.city,
      state: companyData.state,
      country: companyData.country
    }
  };

  const response = await hubspotRequest('/crm/v3/objects/companies', {
    method: 'POST',
    body: JSON.stringify(company)
  });

  return response;
};

// Uso
const company = await createCompany({
  name: 'Acme Corporation',
  domain: 'acme.com',
  industry: 'Technology',
  employees: 500,
  revenue: 50000000,
  city: 'San Francisco',
  state: 'CA',
  country: 'USA'
});
Enter fullscreen mode Exit fullscreen mode

Associando Objetos

const associateContactWithCompany = async (contactId, companyId) => {
  const response = await hubspotRequest(
    `/crm/v3/objects/contacts/${contactId}/associations/companies/${companyId}`,
    {
      method: 'PUT',
      body: JSON.stringify({
        types: [
          {
            associationCategory: 'HUBSPOT_DEFINED',
            associationTypeId: 1 // Contact to Company
          }
        ]
      })
    }
  );

  return response;
};

// Uso
await associateContactWithCompany('12345', '67890');
Enter fullscreen mode Exit fullscreen mode

Tipos de Associação

Associação ID do Tipo Direção
Contato → Empresa 1 Contato está associado à Empresa
Empresa → Contato 1 Empresa tem Contato associado
Negócio → Contato 3 Negócio está associado ao Contato
Negócio → Empresa 5 Negócio está associado à Empresa
Ticket → Contato 16 Ticket está associado ao Contato
Ticket → Empresa 15 Ticket está associado à Empresa

Criando um Negócio

const createDeal = async (dealData) => {
  const deal = {
    properties: {
      dealname: dealData.name,
      amount: dealData.amount.toString(),
      dealstage: dealData.stage || 'appointmentscheduled',
      pipeline: dealData.pipelineId || 'default',
      closedate: dealData.closeDate,
      dealtype: dealData.type || 'newbusiness',
      description: dealData.description
    }
  };

  const response = await hubspotRequest('/crm/v3/objects/deals', {
    method: 'POST',
    body: JSON.stringify(deal)
  });

  return response;
};

// Uso
const deal = await createDeal({
  name: 'Acme Corp - Enterprise License',
  amount: 50000,
  stage: 'qualification',
  closeDate: '2026-06-30',
  type: 'newbusiness',
  description: 'Enterprise annual subscription'
});

// Associe com empresa e contato
await hubspotRequest(
  `/crm/v3/objects/deals/${deal.id}/associations/companies/${companyId}`,
  { method: 'PUT', body: JSON.stringify({ types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 5 }] }) }
);

await hubspotRequest(
  `/crm/v3/objects/deals/${deal.id}/associations/contacts/${contactId}`,
  { method: 'PUT', body: JSON.stringify({ types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 3 }] }) }
);
Enter fullscreen mode Exit fullscreen mode

Estágios do Negócio (Pipeline Padrão)

Estágio Valor Interno
Compromissos Agendados appointmentscheduled
Qualificado para Comprar qualifiedtobuy
Apresentação Agendada presentationscheduled
Tomador de Decisão Comprometido decisionmakerboughtin
Contrato Enviado contractsent
Fechado e Ganho closedwon
Fechado e Perdido closedlost

Webhooks

Configurando Webhooks

const createWebhook = async (webhookData) => {
  const response = await hubspotRequest('/webhooks/v3/my-app/webhooks', {
    method: 'POST',
    body: JSON.stringify({
      webhookUrl: webhookData.url,
      eventTypes: webhookData.events,
      objectType: webhookData.objectType,
      propertyName: webhookData.propertyName // Opcional: filtrar por propriedade
    })
  });

  return response;
};

// Uso
const webhook = await createWebhook({
  url: 'https://myapp.com/webhooks/hubspot',
  events: [
    'contact.creation',
    'contact.propertyChange',
    'company.creation',
    'deal.creation',
    'deal.stageChange'
  ],
  objectType: 'contact'
});

console.log(`Webhook created: ${webhook.id}`);
Enter fullscreen mode Exit fullscreen mode

Tipos de Eventos de Webhook

Tipo de Evento Gatilho
contact.creation Novo contato criado
contact.propertyChange Propriedade de contato atualizada
contact.deletion Contato excluído
company.creation Nova empresa criada
company.propertyChange Propriedade da empresa atualizada
deal.creation Novo negócio criado
deal.stageChange Estágio do negócio alterado
deal.propertyChange Propriedade do negócio atualizada
ticket.creation Novo ticket criado
ticket.propertyChange Propriedade do ticket atualizada

Manipulando Webhooks

const express = require('express');
const crypto = require('crypto');
const app = express();

app.post('/webhooks/hubspot', express.json(), async (req, res) => {
  const signature = req.headers['x-hubspot-signature'];
  const payload = JSON.stringify(req.body);

  // Verifica assinatura do webhook
  const isValid = verifyWebhookSignature(payload, signature, process.env.HUBSPOT_CLIENT_SECRET);

  if (!isValid) {
    console.error('Invalid webhook signature');
    return res.status(401).send('Unauthorized');
  }

  const events = req.body;

  for (const event of events) {
    console.log(`Event: ${event.eventType}`);
    console.log(`Object: ${event.objectType} - ${event.objectId}`);
    console.log(`Property: ${event.propertyName}`);
    console.log(`Value: ${event.propertyValue}`);

    // Redirecione para handler apropriado
    switch (event.eventType) {
      case 'contact.creation':
        await handleContactCreation(event);
        break;
      case 'contact.propertyChange':
        await handleContactUpdate(event);
        break;
      case 'deal.stageChange':
        await handleDealStageChange(event);
        break;
    }
  }

  res.status(200).send('OK');
});

function verifyWebhookSignature(payload, signature, clientSecret) {
  const expectedSignature = crypto
    .createHmac('sha256', clientSecret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature, 'hex'),
    Buffer.from(expectedSignature, 'hex')
  );
}
Enter fullscreen mode Exit fullscreen mode

Limitação de Taxas

Entendendo os Limites de Taxa

Nível Requisições/Segundo Requisições/Dia
Grátis/Inicial 100 100.000
Profissional 200 500.000
Empresarial 400 1.000.000

Se exceder, sua API retorna HTTP 429 (Muitas Requisições).

Cabeçalhos de Limite de Taxa

Cabeçalho Descrição
X-HubSpot-RateLimit-Second-Limit Máx. requisições por segundo
X-HubSpot-RateLimit-Second-Remaining Requisições restantes neste segundo
X-HubSpot-RateLimit-Second-Reset Segundos até o reset do limite por segundo
X-HubSpot-RateLimit-Daily-Limit Máx. requisições por dia
X-HubSpot-RateLimit-Daily-Remaining Requisições restantes hoje
X-HubSpot-RateLimit-Daily-Reset Segundos até o reset do limite diário

Implementando o Tratamento de Limite de Taxas

const makeRateLimitedRequest = async (endpoint, options = {}, maxRetries = 3) => {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await hubspotRequest(endpoint, options);

      // Log de rate limit
      const remaining = response.headers.get('X-HubSpot-RateLimit-Second-Remaining');
      if (remaining < 10) {
        console.warn(`Low rate limit remaining: ${remaining}`);
      }

      return response;
    } catch (error) {
      if (error.message.includes('429') && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Rate limited. Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
};

// Rate limiter
class HubSpotRateLimiter {
  constructor(requestsPerSecond = 90) {
    this.queue = [];
    this.interval = 1000 / requestsPerSecond;
    this.processing = false;
  }

  async add(requestFn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ requestFn, resolve, reject });
      this.process();
    });
  }

  async process() {
    if (this.processing || this.queue.length === 0) return;
    this.processing = true;

    while (this.queue.length > 0) {
      const { requestFn, resolve, reject } = this.queue.shift();
      try {
        const result = await requestFn();
        resolve(result);
      } catch (error) {
        reject(error);
      }
      if (this.queue.length > 0) {
        await new Promise(r => setTimeout(r, this.interval));
      }
    }
    this.processing = false;
  }
}
Enter fullscreen mode Exit fullscreen mode

Lista de Verificação de Implantação em Produção

Antes de ir para produção, garanta:

  • [ ] Use OAuth 2.0 ou aplicativo privado
  • [ ] Armazene tokens em BD criptografado
  • [ ] Implemente atualização automática de tokens
  • [ ] Limitação de taxa e enfileiramento de requisições
  • [ ] Webhook endpoint com HTTPS
  • [ ] Tratamento abrangente de erros
  • [ ] Log para todas as chamadas de API
  • [ ] Monitoramento dos limites de taxa
  • [ ] Runbook para problemas comuns

Casos de Uso no Mundo Real

Sincronização de CRM

Cenário: SaaS sincroniza dados de clientes

  • Desafio: Entrada manual entre app e HubSpot
  • Solução: Sincronização em tempo real via webhooks e API
  • Resultado: Zero digitação manual, dados 100% precisos

Encaminhamento de Leads

Cenário: Agência automatiza distribuição de leads

  • Desafio: Tempo de resposta alto para leads
  • Solução: Encaminhamento por webhook para representantes
  • Resultado: Resposta em 5 minutos, +40% conversão

Conclusão

A API do HubSpot entrega recursos completos de CRM e automação de marketing. Para uma integração sólida:

  • Use OAuth 2.0 para multi-tenant, aplicativo privado para integrações internas
  • Fique atento aos limites de taxa (100–400 req/s)
  • Webhooks para sincronização em tempo real
  • CRM com associações e propriedades customizadas
  • O Apidog potencializa seu fluxo de teste e colaboração em APIs

Seção de Perguntas Frequentes

Como faço para autenticar com a API do HubSpot?

Use OAuth 2.0 para multi-tenant ou aplicativo privado para integrações single-portal. Chaves de API não são mais suportadas.

Quais são os limites de taxa do HubSpot?

De 100 req/s (Grátis) a 400 req/s (Empresarial), e de 100K a 1M de requisições diárias.

Como faço para criar um contato no HubSpot?

Envie um POST para /crm/v3/objects/contacts com email, nome, sobrenome e campos customizados.

Posso criar propriedades personalizadas?

Sim, utilize a API de Propriedades para adicionar campos customizados a qualquer objeto.

Como funcionam os webhooks no HubSpot?

Configure webhooks nas configurações do app. O HubSpot envia POSTs ao seu endpoint para eventos específicos.

Top comments (0)