DEV Community

Cover image for Cara Menggunakan HubSpot API di Tahun 2026
Walse
Walse

Posted on • Originally published at apidog.com

Cara Menggunakan HubSpot API di Tahun 2026

Intisari

HubSpot API memungkinkan pengembang untuk mengintegrasikan hub CRM, pemasaran, penjualan, dan layanan secara terprogram. API ini memakai otentikasi OAuth 2.0 dan aplikasi pribadi, menyediakan endpoint RESTful untuk kontak, perusahaan, penawaran (deals), tiket, dan objek lainnya, serta menerapkan rate limits sesuai tingkat langganan. Panduan berikut membahas setup otentikasi, endpoint inti, webhook, dan strategi integrasi siap-produksi.

Coba Apidog hari ini

Pendahuluan

HubSpot mengelola lebih dari 194.000 akun pelanggan dan miliaran catatan CRM. Untuk pengembang yang membangun integrasi CRM, otomatisasi pemasaran, atau alat penjualan, integrasi HubSpot API sangat penting untuk menjangkau lebih dari 7 juta pengguna.

Faktanya, bisnis kehilangan 15-20 jam per minggu karena entri data manual antar sistem. Integrasi yang solid dengan HubSpot API dapat mengotomatiskan sinkronisasi kontak, pembaruan deal, alur pemasaran, hingga pelaporan lintas platform.

💡 Apidog menyederhanakan pengujian integrasi API. Uji endpoint HubSpot Anda, validasi alur OAuth, cek payload webhook, serta debug masalah otentikasi dalam satu workspace. Impor spesifikasi API, buat mock response, dan kolaborasikan skenario pengujian bersama tim.

Apa Itu HubSpot API?

HubSpot menyediakan API RESTful untuk mengakses data CRM dan fitur otomatisasi pemasaran. API ini mengelola:

  • Kontak, perusahaan, penawaran (deals), tiket, dan objek kustom
  • Email pemasaran & landing page
  • Saluran penjualan dan urutan (sequences)
  • Tiket layanan dan percakapan
  • Analitik & pelaporan
  • Workflow & otomatisasi
  • File dan aset

Fitur Utama

Fitur Deskripsi
Desain RESTful Metode HTTP standar, respons JSON
OAuth 2.0 + Aplikasi Pribadi Opsi otentikasi fleksibel
Webhook Notifikasi real-time perubahan objek
Pembatasan Laju (Rate Limiting) Batasan berdasarkan tingkatan (100-400 req/detik)
Objek CRM Dukungan objek standar & kustom
Asosiasi Menghubungkan objek (misal kontak-perusahaan)
Properti Bidang kustom untuk semua objek
API Pencarian Penyaringan & pengurutan kompleks

Ikhtisar Arsitektur API

HubSpot menggunakan API REST versi:

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

Perbandingan Versi API

Versi Status Otentikasi Kasus Penggunaan
CRM API v3 Saat Ini OAuth 2.0, Aplikasi Pribadi Semua integrasi baru
Automation API v4 Saat Ini OAuth 2.0, Aplikasi Pribadi Pendaftaran workflow
Marketing Email API Saat Ini OAuth 2.0, Aplikasi Pribadi Kampanye email
Contacts API v1 Usang Kunci API (lama) Migrasi ke v3
Companies API v1 Usang Kunci API (lama) Migrasi ke v3

Penting: HubSpot menghentikan otentikasi kunci API. Migrasikan semua integrasi ke OAuth 2.0 atau aplikasi pribadi.

Memulai: Pengaturan Otentikasi

Langkah 1: Buat Akun Pengembang HubSpot

  1. Kunjungi Portal Pengembang HubSpot
  2. Login dengan akun HubSpot (atau buat baru)
  3. Buka menu Aplikasi di dashboard pengembang
  4. Klik Buat aplikasi

Langkah 2: Pilih Metode Otentikasi

HubSpot mendukung dua metode utama:

Metode Terbaik Untuk Tingkat Keamanan
OAuth 2.0 Aplikasi multi-tenant, integrasi publik Tinggi (token cakupan user)
Aplikasi Pribadi Integrasi internal, satu portal Tinggi (token cakupan portal)

Langkah 3: Siapkan Aplikasi Pribadi (Direkomendasikan untuk Integrasi Internal)

  1. Masuk ke Pengaturan > Integrasi > Aplikasi Pribadi
  2. Klik Buat aplikasi pribadi
  3. Pilih scope berikut:
contacts
crm.objects.companies
crm.objects.deals
crm.objects.tickets
automation
webhooks
Enter fullscreen mode Exit fullscreen mode
  1. Buat token akses & simpan dengan aman:
# .env
HUBSPOT_ACCESS_TOKEN="pat-na1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
HUBSPOT_PORTAL_ID="12345678"
Enter fullscreen mode Exit fullscreen mode

Langkah 4: Siapkan OAuth 2.0 (Untuk Multi-Tenant)

  1. Masuk menu Aplikasi > Buat aplikasi
  2. Konfigurasi otentikasi:
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 otorisasi
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

Langkah 5: Tukar Kode untuk Token Akses

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

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

  try {
    const tokens = await exchangeCodeForToken(code);

    // Simpan token ke database
    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

Langkah 6: Refresh Token Akses

Token akses akan kedaluwarsa setelah 6 jam:

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, // Selalu simpan refresh token baru
    expiresIn: data.expires_in
  };
};

// Middleware validasi token
const ensureValidToken = async (portalId) => {
  const installation = await db.installations.findByPortalId(portalId);

  // Refresh jika akan expired dalam 30 menit
  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

Langkah 7: Melakukan Panggilan API Terotentikasi

Buat klien reusable:

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

// Contoh penggunaan
const contacts = await hubspotRequest('/crm/v3/objects/contacts');
Enter fullscreen mode Exit fullscreen mode

Bekerja dengan Objek CRM

Membuat Kontak

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

// Penggunaan
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

Properti Kontak

Properti Tipe Deskripsi
email String Email utama (unik)
firstname String Nama depan
lastname String Nama belakang
phone String No. telepon
company String Nama perusahaan
website String URL situs web
lifecyclestage Enum lead, marketingqualifiedlead, salesqualifiedlead, opportunity, customer, evangelist, subscriber
createdate DateTime Dibuat otomatis
lastmodifieddate DateTime Diperbarui otomatis

Mendapatkan Kontak

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

// Penggunaan
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

Mencari Kontak

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

// Cari semua kontak di perusahaan tertentu
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

Operator Filter Pencarian

Operator Deskripsi Contoh
EQ Sama dengan company EQ 'Acme'
NEQ Tidak sama dengan lifecyclestage NEQ 'subscriber'
CONTAINS_TOKEN Mengandung email CONTAINS_TOKEN 'gmail'
NOT_CONTAINS_TOKEN Tidak mengandung email NOT_CONTAINS_TOKEN 'test'
GT Lebih besar dari createdate GT '2026-01-01'
LT Lebih kecil dari createdate LT '2026-12-31'
GTE Lebih besar/sama dengan deal_amount GTE 10000
LTE Lebih kecil/sama dengan deal_amount LTE 50000
HAS_PROPERTY Memiliki nilai phone HAS_PROPERTY
NOT_HAS_PROPERTY Nilai tidak ada phone NOT_HAS_PROPERTY

Membuat Perusahaan

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

// Penggunaan
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

Menghubungkan Objek

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

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

Jenis Asosiasi

Asosiasi ID Tipe Arah
Kontak → Perusahaan 1 Kontak ke Perusahaan
Perusahaan → Kontak 1 Perusahaan ke Kontak
Penawaran → Kontak 3 Deal ke Kontak
Penawaran → Perusahaan 5 Deal ke Perusahaan
Tiket → Kontak 16 Tiket ke Kontak
Tiket → Perusahaan 15 Tiket ke Perusahaan

Membuat Penawaran (Deal)

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

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

// Hubungkan dengan company dan 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 }] }) }
);
Enter fullscreen mode Exit fullscreen mode

Tahap Penawaran (Pipeline Default)

Tahap Nilai Internal
Janji Temu Terjadwal appointmentscheduled
Memenuhi Syarat untuk Membeli qualifiedtobuy
Presentasi Terjadwal presentationscheduled
Pengambil Keputusan Setuju decisionmakerboughtin
Kontrak Terkirim contractsent
Ditutup Menang closedwon
Ditutup Kalah closedlost

Webhook

Mengonfigurasi Webhook

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 // Optional: filter properti
    })
  });

  return response;
};

// Penggunaan
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

Jenis Event Webhook

Jenis Event Pemicu
contact.creation Kontak baru dibuat
contact.propertyChange Properti kontak diperbarui
contact.deletion Kontak dihapus
company.creation Perusahaan baru dibuat
company.propertyChange Properti perusahaan diperbarui
deal.creation Penawaran baru dibuat
deal.stageChange Tahap penawaran berubah
deal.propertyChange Properti penawaran diperbarui
ticket.creation Tiket baru dibuat
ticket.propertyChange Properti tiket diperbarui

Menangani Webhook

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

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

    // Route ke handler sesuai event
    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

Pembatasan Laju (Rate Limiting)

Memahami Pembatasan Laju

HubSpot menerapkan rate limit berdasarkan tier langganan:

Tingkat Permintaan/Detik Permintaan/Hari
Gratis/Pemula 100 100.000
Profesional 200 500.000
Perusahaan 400 1.000.000

Jika melewati batas, API akan membalas HTTP 429 (Too Many Requests).

Header Rate Limit

Header Deskripsi
X-HubSpot-RateLimit-Second-Limit Batas detik
X-HubSpot-RateLimit-Second-Remaining Sisa permintaan detik ini
X-HubSpot-RateLimit-Second-Reset Detik hingga reset
X-HubSpot-RateLimit-Daily-Limit Batas harian
X-HubSpot-RateLimit-Daily-Remaining Sisa permintaan hari ini
X-HubSpot-RateLimit-Daily-Reset Detik hingga reset harian

Menerapkan Penanganan Rate Limit

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

      // Cek rate limit header
      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
class HubSpotRateLimiter {
  constructor(requestsPerSecond = 90) { // Di bawah limit
    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

Daftar Periksa Deployment Produksi

Sebelum go-live, pastikan:

  • [ ] Menggunakan aplikasi pribadi atau OAuth 2.0
  • [ ] Simpan token secara aman (basis data terenkripsi)
  • [ ] Terapkan refresh token otomatis
  • [ ] Implementasikan rate limit & antrean permintaan
  • [ ] Endpoint webhook di-serve lewat HTTPS
  • [ ] Penanganan error yang komprehensif
  • [ ] Logging setiap call API
  • [ ] Pantau penggunaan rate limit
  • [ ] Siapkan runbook untuk masalah umum

Kasus Penggunaan Dunia Nyata

Sinkronisasi CRM

Perusahaan SaaS menyinkronkan data pelanggan:

  • Tantangan: Entri data manual antara aplikasi dan HubSpot
  • Solusi: Sinkronisasi real-time dengan API & webhook
  • Hasil: Nol entri manual, data akurat 100%

Perutean Prospek

Agen pemasaran mengotomasi distribusi prospek:

  • Tantangan: Respons prospek lambat
  • Solusi: Routing otomatis ke tim sales via webhook
  • Hasil: Respons 5 menit, konversi naik 40%

Kesimpulan

HubSpot API memberi kapabilitas CRM dan pemasaran otomatis yang lengkap. Poin utama:

  • Gunakan OAuth 2.0 untuk aplikasi multi-tenant, aplikasi pribadi untuk internal
  • Rate limit bervariasi (100-400 req/detik)
  • Webhook mendukung sinkronisasi real-time
  • Objek CRM fleksibel, dukung properti & asosiasi kustom
  • Apidog menyederhanakan pengujian API dan kolaborasi tim

Bagian FAQ

Bagaimana cara melakukan otentikasi dengan HubSpot API?

Gunakan OAuth 2.0 untuk aplikasi multi-tenant, atau aplikasi pribadi untuk integrasi satu portal. Kunci API sudah deprecated.

Apa saja batasan laju HubSpot?

Batas mulai 100 request/detik (Gratis) hingga 400/detik (Enterprise), batas harian 100 ribu – 1 juta request.

Bagaimana cara membuat kontak di HubSpot?

Kirim POST ke /crm/v3/objects/contacts dengan properti seperti email, nama depan, nama belakang, dan field kustom lain.

Bisakah saya membuat properti kustom?

Bisa. Pakai API Properti untuk menambah field kustom ke semua objek.

Bagaimana cara kerja webhook di HubSpot?

Konfigurasi webhook melalui pengaturan aplikasi. HubSpot akan mengirim POST ke endpoint Anda saat event terjadi.

Top comments (0)