Comment utiliser l'API HubSpot en 2026

Ashley Innocent

Ashley Innocent

25 March 2026

Comment utiliser l'API HubSpot en 2026

En bref

L'API HubSpot permet aux développeurs de s'intégrer de manière programmatique aux hubs CRM, marketing, ventes et services. Elle utilise l'authentification OAuth 2.0 et des applications privées, des points de terminaison RESTful pour les contacts, les entreprises, les transactions, les tickets, et plus encore, avec des limites de débit basées sur le niveau d'abonnement. Ce guide couvre la configuration de l'authentification, les points de terminaison principaux, les webhooks et les stratégies d'intégration en production.

Introduction

HubSpot gère plus de 194 000 comptes clients et des milliards d'enregistrements CRM. Pour les développeurs qui créent des intégrations CRM, de l'automatisation marketing ou des outils de vente, l'intégration de l'API HubSpot n'est pas une option, elle est essentielle pour atteindre plus de 7 millions d'utilisateurs.

Voici la réalité : les entreprises perdent 15 à 20 heures par semaine en saisie manuelle de données entre les systèmes. Une intégration solide de l'API HubSpot automatise la synchronisation des contacts, les mises à jour des transactions, les flux de travail marketing et le reporting sur toutes les plateformes.

💡
Apidog simplifie les tests d'intégration d'API. Testez vos points de terminaison HubSpot, validez les flux OAuth, inspectez les charges utiles des webhooks et déboguez les problèmes d'authentification dans un seul espace de travail. Importez des spécifications d'API, simulez des réponses et partagez des scénarios de test avec votre équipe.
button

Qu'est-ce que l'API HubSpot ?

HubSpot fournit une API RESTful pour accéder aux données CRM et aux fonctionnalités d'automatisation marketing. L'API gère :

Fonctionnalités clés

Fonctionnalité Description
Conception RESTful Méthodes HTTP standard avec réponses JSON
OAuth 2.0 + Applications privées Options d'authentification flexibles
Webhooks Notifications en temps réel des changements d'objets
Limitation de débit Limites basées sur le niveau (100-400 requêtes/seconde)
Objets CRM Prise en charge des objets standard et personnalisés
Associations Lier des objets (contact-entreprise, transaction-contact)
Propriétés Champs personnalisés pour tout type d'objet
API de recherche Filtrage et tri complexes

Vue d'ensemble de l'architecture de l'API

HubSpot utilise des API REST versionnées :

https://api.hubapi.com/

Comparaison des versions de l'API

Version Statut Authentification Cas d'utilisation
API CRM v3 Actuelle OAuth 2.0, Application privée Toutes les nouvelles intégrations
API d'automatisation v4 Actuelle OAuth 2.0, Application privée Inscription au flux de travail
API E-mail marketing Actuelle OAuth 2.0, Application privée Campagnes d'e-mail
API Contacts v1 Obsolète Clé API (héritée) Migrer vers v3
API Entreprises v1 Obsolète Clé API (héritée) Migrer vers v3

Important : HubSpot a déprécié l'authentification par clé API au profit d'OAuth 2.0 et des applications privées. Migrez toutes les intégrations immédiatement.

Premiers pas : Configuration de l'authentification

Étape 1 : Créez votre compte développeur HubSpot

Avant d'accéder à l'API :

  1. Visitez le Portail des développeurs HubSpot
  2. Connectez-vous avec votre compte HubSpot (ou créez-en un)
  3. Naviguez vers Applications dans le tableau de bord des développeurs
  4. Cliquez sur Créer une application

Étape 2 : Choisissez la méthode d'authentification

HubSpot prend en charge deux méthodes d'authentification :

Méthode Idéale pour Niveau de sécurité
OAuth 2.0 Applications multi-locataires, intégrations publiques Élevé (jetons étendus à l'utilisateur)
Application privée Intégrations internes, portail unique Élevé (jeton étendu au portail)

Étape 3 : Configurer une application privée (recommandé pour les intégrations internes)

Créez une application privée pour un accès à un portail unique :

  1. Allez dans Paramètres > Intégrations > Applications privées
  2. Cliquez sur Créer une application privée
  3. Configurez les étendues :
contacts
crm.objects.companies
crm.objects.deals
crm.objects.tickets
automation
webhooks
  1. Générez un jeton d'accès
  2. Copiez et stockez en toute sécurité
# fichier .env
HUBSPOT_ACCESS_TOKEN="pat-na1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
HUBSPOT_PORTAL_ID="12345678"

Étape 4 : Configurer OAuth 2.0 (pour les applications multi-locataires)

Configurez OAuth pour un accès multi-portails :

  1. Allez dans Applications > Créer une application
  2. Configurez les paramètres d'authentification :
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;

// Construire l'URL d'autorisation
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()}`;
};

Étape 5 : Échangez le code contre un jeton d'accès

Gérez le rappel 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
  };
};

// Gérer le rappel
app.get('/oauth/callback', async (req, res) => {
  const { code, state } = req.query;

  try {
    const tokens = await exchangeCodeForToken(code);

    // Stocker les jetons dans la base de données
    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('Erreur OAuth :', error);
    res.status(500).send('Échec de l\'authentification');
  }
});

Étape 6 : Actualiser le jeton d'accès

Les jetons d'accès expirent après 6 heures :

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, // Toujours enregistrer le nouveau jeton d'actualisation
    expiresIn: data.expires_in
  };
};

// Middleware pour assurer un jeton valide
const ensureValidToken = async (portalId) => {
  const installation = await db.installations.findByPortalId(portalId);

  // Actualiser s'il expire dans les 30 minutes
  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;
};

Étape 7 : Effectuer des appels API authentifiés

Créez un client API réutilisable :

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

  return response.json();
};

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

Travailler avec les objets CRM

Création d'un contact

Créer ou mettre à jour un contact :

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

// Utilisation
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 créé : ${contact.id}`);

Propriétés des contacts

Propriété Type Description
email Chaîne de caractères E-mail principal (identifiant unique)
firstname Chaîne de caractères Prénom
lastname Chaîne de caractères Nom de famille
phone Chaîne de caractères Numéro de téléphone
company Chaîne de caractères Nom de l'entreprise
website Chaîne de caractères URL du site web
lifecyclestage Énumération lead, marketingqualifiedlead, salesqualifiedlead, opportunity, customer, evangelist, subscriber
createdate DateTime Généré automatiquement
lastmodifieddate DateTime Généré automatiquement

Obtenir un contact

Récupérer un contact par ID :

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

// Utilisation
const contact = await getContact('12345');
console.log(`${contact.properties.firstname} ${contact.properties.lastname}`);
console.log(`E-mail : ${contact.properties.email}`);

Recherche de contacts

Recherche avec filtres :

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

// Utilisation - Trouver des contacts dans une entreprise spécifique
const results = await searchContacts({
  filterGroups: [
    {
      filters: [
        {
          propertyName: 'company',
          operator: 'EQ',
          value: 'Acme Corp'
        }
      ]
    }
  ]
});

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

Opérateurs de filtre de recherche

Opérateur Description Exemple
EQ Égal à company EQ 'Acme'
NEQ Non égal à lifecyclestage NEQ 'subscriber'
CONTAINS_TOKEN Contient email CONTAINS_TOKEN 'gmail'
NOT_CONTAINS_TOKEN Ne contient pas email NOT_CONTAINS_TOKEN 'test'
GT Supérieur à createdate GT '2026-01-01'
LT Inférieur à createdate LT '2026-12-31'
GTE Supérieur ou égal deal_amount GTE 10000
LTE Inférieur ou égal deal_amount LTE 50000
HAS_PROPERTY A une valeur phone HAS_PROPERTY
NOT_HAS_PROPERTY Valeur manquante phone NOT_HAS_PROPERTY

Création d'une entreprise

Créer un enregistrement d'entreprise :

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

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

Association d'objets

Lier les contacts aux entreprises :

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 vers Entreprise
          }
        ]
      })
    }
  );

  return response;
};

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

Types d'association

Association ID de type Direction
Contact → Entreprise 1 Le contact est associé à l'entreprise
Entreprise → Contact 1 L'entreprise a un contact associé
Transaction → Contact 3 La transaction est associée au contact
Transaction → Entreprise 5 La transaction est associée à l'entreprise
Ticket → Contact 16 Le ticket est associé au contact
Ticket → Entreprise 15 Le ticket est associé à l'entreprise

Création d'une transaction

Créer une opportunité de vente :

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

// Utilisation
const deal = await createDeal({
  name: 'Acme Corp - Licence Entreprise',
  amount: 50000,
  stage: 'qualification',
  closeDate: '2026-06-30',
  type: 'newbusiness',
  description: 'Abonnement annuel entreprise'
});

// Associer avec l'entreprise et le contact
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 }] }) }
);

Étapes de transaction (pipeline par défaut)

Étape Valeur interne
Rendez-vous programmés appointmentscheduled
Qualifié pour acheter qualifiedtobuy
Présentation programmée presentationscheduled
Décideur convaincu decisionmakerboughtin
Contrat envoyé contractsent
Fermée gagnée closedwon
Fermée perdue closedlost

Webhooks

Configuration des Webhooks

Configurez des webhooks pour des notifications en temps réel :

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 // Facultatif : filtrer par changement de propriété
    })
  });

  return response;
};

// Utilisation
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 créé : ${webhook.id}`);

Types d'événements de webhook

Type d'événement Déclencheur
contact.creation Nouveau contact créé
contact.propertyChange Propriété du contact mise à jour
contact.deletion Contact supprimé
company.creation Nouvelle entreprise créée
company.propertyChange Propriété de l'entreprise mise à jour
deal.creation Nouvelle transaction créée
deal.stageChange Étape de la transaction modifiée
deal.propertyChange Propriété de la transaction mise à jour
ticket.creation Nouveau ticket créé
ticket.propertyChange Propriété du ticket mise à jour

Gestion des 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);

  // Vérifier la signature du webhook
  const isValid = verifyWebhookSignature(payload, signature, process.env.HUBSPOT_CLIENT_SECRET);

  if (!isValid) {
    console.error('Signature de webhook invalide');
    return res.status(401).send('Non autorisé');
  }

  const events = req.body;

  for (const event of events) {
    console.log(`Événement : ${event.eventType}`);
    console.log(`Objet : ${event.objectType} - ${event.objectId}`);
    console.log(`Propriété : ${event.propertyName}`);
    console.log(`Valeur : ${event.propertyValue}`);

    // Acheminer vers le gestionnaire approprié
    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')
  );
}

Limitation de débit

Comprendre les limites de débit

HubSpot applique des limites de débit basées sur le niveau d'abonnement :

Niveau Requêtes/Seconde Requêtes/Jour
Gratuit/Starter 100 100 000
Professionnel 200 500 000
Entreprise 400 1 000 000

Dépasser les limites entraîne des réponses HTTP 429 (Trop de requêtes).

En-têtes de limitation de débit

En-tête Description
X-HubSpot-RateLimit-Second-Limit Nb max. de requêtes par seconde
X-HubSpot-RateLimit-Second-Remaining Nb de requêtes restantes cette seconde
X-HubSpot-RateLimit-Second-Reset Secondes avant la réinitialisation de la limite par seconde
X-HubSpot-RateLimit-Daily-Limit Nb max. de requêtes par jour
X-HubSpot-RateLimit-Daily-Remaining Nb de requêtes restantes aujourd'hui
X-HubSpot-RateLimit-Daily-Reset Secondes avant la réinitialisation de la limite quotidienne

Mise en œuvre de la gestion de la limitation de débit

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

      // Informations de journalisation sur la limite de débit
      const remaining = response.headers.get('X-HubSpot-RateLimit-Second-Remaining');
      if (remaining < 10) {
        console.warn(`Faible limite de débit restante : ${remaining}`);
      }

      return response;
    } catch (error) {
      if (error.message.includes('429') && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Limite de débit atteinte. Nouvelle tentative dans ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
};

// Classe de limitation de débit
class HubSpotRateLimiter {
  constructor(requestsPerSecond = 90) { // Rester sous la limite
    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;
  }
}

Liste de contrôle pour le déploiement en production

Avant de passer en direct :


Cas d'utilisation concrets

Synchronisation CRM

Une entreprise SaaS synchronise les données clients :

Routage des prospects

Une agence de marketing automatise la distribution des prospects :

Conclusion

L'API HubSpot offre des capacités complètes en matière de CRM et d'automatisation marketing. Points clés à retenir :

button

Section FAQ

Comment s'authentifier avec l'API HubSpot ?

Utilisez OAuth 2.0 pour les applications multi-locataires ou les applications privées pour les intégrations à portail unique. L'authentification par clé API est obsolète.

Quelles sont les limites de débit de HubSpot ?

Les limites de débit vont de 100 requêtes/seconde (Gratuit) à 400 requêtes/seconde (Entreprise), avec des limites quotidiennes de 100 000 à 1 million de requêtes.

Comment créer un contact dans HubSpot ?

POST sur /crm/v3/objects/contacts avec les propriétés, y compris l'e-mail, le prénom, le nom de famille et tous les champs personnalisés.

Puis-je créer des propriétés personnalisées ?

Oui, utilisez l'API Propriétés pour créer des champs personnalisés pour tout type d'objet.

Comment fonctionnent les webhooks dans HubSpot ?

Configurez les webhooks dans les paramètres de votre application. HubSpot envoie des requêtes POST à votre point de terminaison lorsque des événements spécifiés se produisent.

Pratiquez le Design-first d'API dans Apidog

Découvrez une manière plus simple de créer et utiliser des API