Cómo Usar la API de HubSpot en 2026

Ashley Innocent

Ashley Innocent

25 March 2026

Cómo Usar la API de HubSpot en 2026

TL;DR

La API de HubSpot permite a los desarrolladores integrarse programáticamente con los hubs de CRM, marketing, ventas y servicio. Utiliza autenticación OAuth 2.0 y de aplicaciones privadas, endpoints RESTful para contactos, empresas, negocios, tickets y más, con límites de tasa basados en el nivel de suscripción. Esta guía cubre la configuración de autenticación, los endpoints principales, los webhooks y las estrategias de integración en producción.

Introducción

HubSpot gestiona más de 194.000 cuentas de clientes y miles de millones de registros de CRM. Para los desarrolladores que crean integraciones de CRM, automatización de marketing o herramientas de ventas, la integración con la API de HubSpot no es opcional, es esencial para llegar a más de 7 millones de usuarios.

Esta es la realidad: las empresas pierden entre 15 y 20 horas semanales en la introducción manual de datos entre sistemas. Una sólida integración con la API de HubSpot automatiza la sincronización de contactos, las actualizaciones de negocios, los flujos de trabajo de marketing y los informes en todas las plataformas.

💡
Apidog simplifica las pruebas de integración de API. Pruebe sus endpoints de HubSpot, valide flujos de OAuth, inspeccione cargas útiles de webhook y depure problemas de autenticación en un solo espacio de trabajo. Importe especificaciones de API, simule respuestas y comparta escenarios de prueba con su equipo.
button

¿Qué es la API de HubSpot?

HubSpot proporciona una API RESTful para acceder a los datos de CRM y a las funciones de automatización de marketing. La API gestiona:

Características Clave

Característica Descripción
Diseño RESTful Métodos HTTP estándar con respuestas JSON
OAuth 2.0 + Apps Privadas Opciones de autenticación flexibles
Webhooks Notificaciones en tiempo real para cambios de objetos
Limitación de Tasa Límites basados en niveles (100-400 solicitudes/segundo)
Objetos CRM Soporte para objetos estándar y personalizados
Asociaciones Vincular objetos (contacto-empresa, negocio-contacto)
Propiedades Campos personalizados para cualquier tipo de objeto
API de Búsqueda Filtrado y clasificación complejos

Descripción General de la Arquitectura de la API

HubSpot utiliza APIs REST versionadas:

https://api.hubapi.com/

Versiones de la API Comparadas

Versión Estado Autenticación Caso de Uso
CRM API v3 Actual OAuth 2.0, App Privada Todas las nuevas integraciones
Automation API v4 Actual OAuth 2.0, App Privada Inscripción en flujos de trabajo
Marketing Email API Actual OAuth 2.0, App Privada Campañas de email
Contacts API v1 Obsoleta Clave API (legado) Migrar a v3
Companies API v1 Obsoleta Clave API (legado) Migrar a v3

Importante: HubSpot ha dejado de usar la autenticación con clave API en favor de OAuth 2.0 y las aplicaciones privadas. Migre todas las integraciones inmediatamente.

Primeros Pasos: Configuración de Autenticación

Paso 1: Cree su Cuenta de Desarrollador de HubSpot

Antes de acceder a la API:

  1. Visite el Portal de Desarrolladores de HubSpot
  2. Inicie sesión con su cuenta de HubSpot (o cree una)
  3. Navegue a Apps en el panel de desarrolladores
  4. Haga clic en Crear app

Paso 2: Elija el Método de Autenticación

HubSpot soporta dos métodos de autenticación:

Método Mejor para Nivel de Seguridad
OAuth 2.0 Aplicaciones multi-tenant, integraciones públicas Alto (tokens con alcance de usuario)
App Privada Integraciones internas, portal único Alto (token con alcance de portal)

Paso 3: Configurar Aplicación Privada (Recomendado para Integraciones Internas)

Cree una aplicación privada para acceso de portal único:

  1. Vaya a Configuración > Integraciones > Aplicaciones Privadas
  2. Haga clic en Crear una aplicación privada
  3. Configure los ámbitos (scopes):
contacts
crm.objects.companies
crm.objects.deals
crm.objects.tickets
automation
webhooks
  1. Genere un token de acceso
  2. Cópielo y guárdelo de forma segura
# archivo .env
HUBSPOT_ACCESS_TOKEN="pat-na1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
HUBSPOT_PORTAL_ID="12345678"

Paso 4: Configurar OAuth 2.0 (Para Aplicaciones Multi-tenant)

Configure OAuth para acceso a múltiples portales:

  1. Vaya a Apps > Crear app
  2. Configure los ajustes de autenticación:
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;

// Construir URL de autorización
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()}`;
};

Paso 5: Intercambiar Código por Token de Acceso

Manejar la devolución de llamada de OAuth:

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
  };
};

// Manejar la devolución de llamada
app.get('/oauth/callback', async (req, res) => {
  const { code, state } = req.query;

  try {
    const tokens = await exchangeCodeForToken(code);

    // Almacenar tokens en la base de datos
    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('Error de OAuth:', error);
    res.status(500).send('Autenticación fallida');
  }
});

Paso 6: Refrescar Token de Acceso

Los tokens de acceso expiran después de 6 horas:

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,
      refresh_token: refreshToken
    })
  });

  const data = await response.json();

  return {
    accessToken: data.access_token,
    refreshToken: data.refresh_token, // Siempre guarda el nuevo refresh token
    expiresIn: data.expires_in
  };
};

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

  // Refrescar si expira dentro de 30 minutos
  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;
};

Paso 7: Realizar Llamadas a la API Autenticadas

Crear un cliente de API reutilizable:

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(`Error de la API de HubSpot: ${error.message}`);
  }

  return response.json();
};

// Uso
const contacts = await hubspotRequest('/crm/v3/objects/contacts');

Trabajando con Objetos CRM

Creando un Contacto

Crear o actualizar un contacto:

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(`Contacto creado: ${contact.id}`);

Propiedades del Contacto

Propiedad Tipo Descripción
email Cadena Email principal (identificador único)
firstname Cadena Nombre
lastname Cadena Apellido
phone Cadena Número de teléfono
company Cadena Nombre de la empresa
website Cadena URL del sitio web
lifecyclestage Enumeración lead, marketingqualifiedlead, salesqualifiedlead, opportunity, customer, evangelist, subscriber
createdate Fecha y Hora Generado automáticamente
lastmodifieddate Fecha y Hora Generado automáticamente

Obteniendo un Contacto

Obtener contacto por ID:

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}`);

Buscando Contactos

Buscar con filtros:

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;
};

// Uso - Encontrar contactos en una empresa específica
const results = await searchContacts({
  filterGroups: [
    {
      filters: [
        {
          propertyName: 'company',
          operator: 'EQ',
          value: 'Acme Corp'
        }
      ]
    }
  ]
});

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

Operadores de Filtro de Búsqueda

Operador Descripción Ejemplo
EQ Igual a company EQ 'Acme'
NEQ No igual a lifecyclestage NEQ 'subscriber'
CONTAINS_TOKEN Contiene email CONTAINS_TOKEN 'gmail'
NOT_CONTAINS_TOKEN No contiene email NOT_CONTAINS_TOKEN 'test'
GT Mayor que createdate GT '2026-01-01'
LT Menor que createdate LT '2026-12-31'
GTE Mayor o igual deal_amount GTE 10000
LTE Menor o igual deal_amount LTE 50000
HAS_PROPERTY Tiene valor phone HAS_PROPERTY
NOT_HAS_PROPERTY Valor faltante phone NOT_HAS_PROPERTY

Creando una Empresa

Crear registro de 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'
});

Asociando Objetos

Vincular contactos a empresas:

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 // Contacto a Empresa
          }
        ]
      })
    }
  );

  return response;
};

// Uso
await associateContactWithCompany('12345', '67890');

Tipos de Asociación

Asociación ID de Tipo Dirección
Contacto → Empresa 1 El contacto está asociado con la empresa
Empresa → Contacto 1 La empresa tiene un contacto asociado
Negocio → Contacto 3 El negocio está asociado con el contacto
Negocio → Empresa 5 El negocio está asociado con la empresa
Ticket → Contacto 16 El ticket está asociado con el contacto
Ticket → Empresa 15 El ticket está asociado con la empresa

Creando un Negocio

Crear oportunidad de venta:

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 - Licencia Empresarial',
  amount: 50000,
  stage: 'qualification',
  closeDate: '2026-06-30',
  type: 'newbusiness',
  description: 'Suscripción anual empresarial'
});

// Asociar con empresa y contacto
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 }] }) }
);

Etapas de Negocio (Embudo por Defecto)

Etapa Valor Interno
Citas Programadas appointmentscheduled
Calificado para Comprar qualifiedtobuy
Presentación Programada presentationscheduled
Responsable de la Toma de Decisiones Comprometido decisionmakerboughtin
Contrato Enviado contractsent
Cerrado Ganado closedwon
Cerrado Perdido closedlost

Webhooks

Configurando Webhooks

Configure webhooks para notificaciones en tiempo real:

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 cambio de propiedad
    })
  });

  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 creado: ${webhook.id}`);

Tipos de Eventos de Webhook

Tipo de Evento Disparador
contact.creation Nuevo contacto creado
contact.propertyChange Propiedad de contacto actualizada
contact.deletion Contacto eliminado
company.creation Nueva empresa creada
company.propertyChange Propiedad de empresa actualizada
deal.creation Nuevo negocio creado
deal.stageChange Etapa de negocio cambiada
deal.propertyChange Propiedad de negocio actualizada
ticket.creation Nuevo ticket creado
ticket.propertyChange Propiedad de ticket actualizada

Manejo de 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);

  // Verificar firma del webhook
  const isValid = verifyWebhookSignature(payload, signature, process.env.HUBSPOT_CLIENT_SECRET);

  if (!isValid) {
    console.error('Firma de webhook inválida');
    return res.status(401).send('No autorizado');
  }

  const events = req.body;

  for (const event of events) {
    console.log(`Evento: ${event.eventType}`);
    console.log(`Objeto: ${event.objectType} - ${event.objectId}`);
    console.log(`Propiedad: ${event.propertyName}`);
    console.log(`Valor: ${event.propertyValue}`);

    // Dirigir al manejador apropiado
    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')
  );
}

Limitación de Tasa

Entendiendo los Límites de Tasa

HubSpot aplica límites de tasa basados en el nivel de suscripción:

Nivel Solicitudes/Segundo Solicitudes/Día
Gratis/Starter 100 100.000
Profesional 200 500.000
Empresarial 400 1.000.000

Exceder los límites resulta en respuestas HTTP 429 (Demasiadas Solicitudes).

Encabezados de Límite de Tasa

Encabezado Descripción
X-HubSpot-RateLimit-Second-Limit Máximo de solicitudes por segundo
X-HubSpot-RateLimit-Second-Remaining Solicitudes restantes este segundo
X-HubSpot-RateLimit-Second-Reset Segundos hasta que se restablezca el límite de segundo
X-HubSpot-RateLimit-Daily-Limit Máximo de solicitudes por día
X-HubSpot-RateLimit-Daily-Remaining Solicitudes restantes hoy
X-HubSpot-RateLimit-Daily-Reset Segundos hasta que se restablezca el límite diario

Implementando el Manejo de Límites de Tasa

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

      // Registrar información de límite de tasa
      const remaining = response.headers.get('X-HubSpot-RateLimit-Second-Remaining');
      if (remaining < 10) {
        console.warn(`Límite de tasa bajo restante: ${remaining}`);
      }

      return response;
    } catch (error) {
      if (error.message.includes('429') && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Límite de tasa alcanzado. Reintentando en ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
};

// Clase de limitador de tasa
class HubSpotRateLimiter {
  constructor(requestsPerSecond = 90) { // Mantenerse por debajo del límite
    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;
  }
}

Lista de Verificación para Despliegue en Producción

Antes de salir en vivo:


Casos de Uso en el Mundo Real

Sincronización de CRM

Una empresa SaaS sincroniza los datos de los clientes:

Enrutamiento de Leads

Una agencia de marketing automatiza la distribución de leads:

Conclusión

La API de HubSpot proporciona capacidades integrales de CRM y automatización de marketing. Puntos clave:

button

Sección de Preguntas Frecuentes

¿Cómo me autentico con la API de HubSpot?

Utilice OAuth 2.0 para aplicaciones multi-tenant o aplicaciones privadas para integraciones de portal único. La autenticación con clave API está obsoleta.

¿Cuáles son los límites de tasa de HubSpot?

Los límites de tasa varían de 100 solicitudes/segundo (Gratis) a 400 solicitudes/segundo (Empresarial), con límites diarios de 100K a 1M de solicitudes.

¿Cómo creo un contacto en HubSpot?

Realice una solicitud POST a /crm/v3/objects/contacts con propiedades que incluyan email, firstname, lastname y cualquier campo personalizado.

¿Puedo crear propiedades personalizadas?

Sí, utilice la API de Propiedades para crear campos personalizados para cualquier tipo de objeto.

¿Cómo funcionan los webhooks en HubSpot?

Configure los webhooks en la configuración de su aplicación. HubSpot envía solicitudes POST a su endpoint cuando ocurren eventos específicos.

Practica el diseño de API en Apidog

Descubre una forma más fácil de construir y usar APIs