DEV Community

Cover image for Cách Sử Dụng HubSpot API Hiệu Quả Năm 2026
Sebastian Petrus
Sebastian Petrus

Posted on • Originally published at apidog.com

Cách Sử Dụng HubSpot API Hiệu Quả Năm 2026

TÓM TẮT

API của HubSpot cho phép các nhà phát triển tích hợp với CRM, marketing, bán hàng, dịch vụ. Sử dụng xác thực OAuth 2.0 và ứng dụng riêng tư, hỗ trợ RESTful endpoints cho danh bạ, công ty, giao dịch, phiếu hỗ trợ, v.v. Bài này hướng dẫn từng bước thiết lập xác thực, gọi API, cấu hình Webhook và chiến lược vận hành sản xuất.

Hãy thử Apidog ngay hôm nay

Giới thiệu

HubSpot quản lý hàng trăm nghìn tài khoản khách hàng, hàng tỷ bản ghi CRM. Khi tự động hóa marketing, CRM hay bán hàng, tích hợp API HubSpot là bước bắt buộc để đồng bộ dữ liệu cho hàng triệu người dùng.

Thực tế, doanh nghiệp mất hàng chục giờ nhập liệu thủ công mỗi tuần. Tích hợp API HubSpot giúp tự động đồng bộ danh bạ, cập nhật giao dịch, workflow marketing, báo cáo và giảm lỗi nhập dữ liệu.

💡 Apidog đơn giản hóa kiểm thử tích hợp API: test endpoint HubSpot, xác thực OAuth, kiểm tra webhook, debug xác thực trong một workspace. Nhập spec API, tạo mock response, chia sẻ test scenario cho team.

API của HubSpot là gì?

HubSpot cung cấp API RESTful để truy cập dữ liệu CRM, tự động hóa marketing:

  • Danh bạ, công ty, giao dịch, phiếu hỗ trợ, đối tượng tùy chỉnh
  • Email marketing, landing page
  • Quy trình bán hàng, chuỗi workflow
  • Hỗ trợ, hội thoại
  • Analytics & báo cáo
  • Workflow & automation
  • File & asset management

Các tính năng chính

Tính năng Mô tả
Thiết kế RESTful HTTP chuẩn, JSON response
OAuth 2.0 & Ứng dụng riêng tư Xác thực linh hoạt
Webhooks Nhận realtime notification khi đối tượng thay đổi
Giới hạn tốc độ 100-400 requests/giây, tùy gói
Đối tượng CRM Hỗ trợ cả object chuẩn và custom
Liên kết Kết nối đối tượng (contact-company, deal-contact, ...)
Thuộc tính Custom field cho mọi object
API Tìm kiếm Lọc/sắp xếp phức tạp

Tổng quan kiến trúc API

HubSpot API có phiên bản:

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

So sánh các phiên bản API

Phiên bản Trạng thái Xác thực Trường hợp sử dụng
API CRM v3 Hiện hành OAuth 2.0, App riêng Tích hợp mới
API Automation v4 Hiện hành OAuth 2.0, App riêng Ghi danh workflow
API Email Marketing Hiện hành OAuth 2.0, App riêng Chiến dịch email
API Danh bạ v1 Đã ngừng hỗ trợ API Key (cũ) Di chuyển sang v3
API Công ty v1 Đã ngừng hỗ trợ API Key (cũ) Di chuyển sang v3

Lưu ý: Xác thực bằng API key đã ngừng hỗ trợ, phải dùng OAuth 2.0 hoặc ứng dụng riêng tư.

Bắt đầu: Thiết lập xác thực

Bước 1: Tạo tài khoản Developer HubSpot

  1. Truy cập Cổng thông tin nhà phát triển HubSpot
  2. Đăng nhập/tạo tài khoản mới
  3. Vào Ứng dụng trong dashboard Developer
  4. Nhấn Tạo ứng dụng

Bước 2: Chọn phương thức xác thực

Phương thức Dùng cho Bảo mật
OAuth 2.0 App đa tenant, tích hợp công khai Cao (token user)
App riêng tư Nội bộ, 1 portal Cao (token portal)

Bước 3: Tạo ứng dụng riêng tư (Khuyên dùng cho tích hợp nội bộ)

  1. Vào Cài đặt > Tích hợp > Ứng dụng riêng tư
  2. Nhấn Tạo ứng dụng riêng tư
  3. Chọn scope:
contacts
crm.objects.companies
crm.objects.deals
crm.objects.tickets
automation
webhooks
Enter fullscreen mode Exit fullscreen mode
  1. Tạo mã truy cập, lưu trữ an toàn
# .env
HUBSPOT_ACCESS_TOKEN="pat-na1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
HUBSPOT_PORTAL_ID="12345678"
Enter fullscreen mode Exit fullscreen mode

Bước 4: Thiết lập OAuth 2.0 (App đa tenant)

  1. Vào Ứng dụng > Tạo ứng dụng
  2. Cấu hình xác thực:
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;

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

Bước 5: Trao đổi mã lấy access token

const exchangeCodeForToken = async (code) => {
  const response = await fetch('https://api.hubspot.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
  };
};

// Xử lý callback
app.get('/oauth/callback', async (req, res) => {
  const { code, state } = req.query;
  try {
    const tokens = await exchangeCodeForToken(code);
    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

Bước 6: Làm mới access token

const refreshAccessToken = async (refreshToken) => {
  const response = await fetch('https://api.hubspot.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,
    expiresIn: data.expires_in
  };
};

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

Bước 7: Gọi API đã xác thực

const HUBSPOT_BASE_URL = 'https://api.hubspot.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();
};

// Ví dụ:
const contacts = await hubspotRequest('/crm/v3/objects/contacts');
Enter fullscreen mode Exit fullscreen mode

Làm việc với các đối tượng CRM

Tạo liên hệ

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

// Sử dụng
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

Thuộc tính liên hệ

Thuộc tính Loại Mô tả
email Chuỗi Email chính (unique)
firstname Chuỗi Tên
lastname Chuỗi Họ
phone Chuỗi Số điện thoại
company Chuỗi Tên công ty
website Chuỗi URL trang web
lifecyclestage Enum lead, marketingqualifiedlead, ...
createdate Ngày giờ Tự động tạo
lastmodifieddate Ngày giờ Tự động tạo

Lấy liên hệ theo ID

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

// Sử dụng
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

Tìm kiếm liên hệ

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

// Tìm contact thuộc công ty cụ thể
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

Các toán tử lọc tìm kiếm

Toán tử Mô tả Ví dụ
EQ Bằng company EQ 'Acme'
NEQ Không bằng lifecyclestage NEQ 'subscriber'
CONTAINS_TOKEN Chứa email CONTAINS_TOKEN 'gmail'
NOT_CONTAINS_TOKEN Không chứa email NOT_CONTAINS_TOKEN 'test'
GT Lớn hơn createdate GT '2026-01-01'
LT Nhỏ hơn createdate LT '2026-12-31'
GTE >= deal_amount GTE 10000
LTE <= deal_amount LTE 50000
HAS_PROPERTY Có giá trị phone HAS_PROPERTY
NOT_HAS_PROPERTY Thiếu giá trị phone NOT_HAS_PROPERTY

Tạo công ty

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

// Sử dụng
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

Liên kết các đối tượng

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

// Sử dụng
await associateContactWithCompany('12345', '67890');
Enter fullscreen mode Exit fullscreen mode

Các loại liên kết

Liên kết ID loại Hướng
Liên hệ → Công ty 1 Liên hệ được liên kết với Công ty
Công ty → Liên hệ 1 Công ty có liên hệ liên kết
Giao dịch → Liên hệ 3 Giao dịch liên kết Liên hệ
Giao dịch → Công ty 5 Giao dịch liên kết Công ty
Phiếu hỗ trợ → Liên hệ 16 Phiếu hỗ trợ liên kết Liên hệ
Phiếu hỗ trợ → Công ty 15 Phiếu hỗ trợ liên kết Công ty

Tạo giao dịch (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;
};

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

// Liên kết với company và 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

Giai đoạn giao dịch mặc định

Giai đoạn Giá trị nội bộ
Cuộc hẹn đã được lên lịch appointmentscheduled
Đủ điều kiện mua qualifiedtobuy
Buổi trình bày đã được lên lịch presentationscheduled
Người ra quyết định đã tham gia decisionmakerboughtin
Hợp đồng đã gửi contractsent
Đã chốt thành công closedwon
Đã mất closedlost

Webhooks

Cấu hình 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
    })
  });

  return response;
};

// Sử dụng
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

Các loại sự kiện webhook

Loại sự kiện Kích hoạt
contact.creation Liên hệ mới tạo
contact.propertyChange Liên hệ thay đổi thuộc tính
contact.deletion Liên hệ bị xóa
company.creation Công ty mới tạo
company.propertyChange Công ty thay đổi thuộc tính
deal.creation Giao dịch mới tạo
deal.stageChange Giao dịch đổi giai đoạn
deal.propertyChange Giao dịch đổi thuộc tính
ticket.creation Phiếu hỗ trợ mới tạo
ticket.propertyChange Phiếu hỗ trợ đổi thuộc tính

Xử lý 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);

  // Xác thực 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}`);

    // Xử lý tùy loại 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

Giới hạn tốc độ

Hiểu về giới hạn tốc độ

Cấp độ Yêu cầu/giây Yêu cầu/ngày
Miễn phí/Khởi đầu 100 100.000
Chuyên nghiệp 200 500.000
Doanh nghiệp 400 1.000.000

Vượt giới hạn sẽ trả về HTTP 429.

Header giới hạn tốc độ

Header Ý nghĩa
X-HubSpot-RateLimit-Second-Limit Max request/giây
X-HubSpot-RateLimit-Second-Remaining Request còn lại trong 1 giây
X-HubSpot-RateLimit-Second-Reset Số giây đến khi reset lại
X-HubSpot-RateLimit-Daily-Limit Max request/ngày
X-HubSpot-RateLimit-Daily-Remaining Request còn lại hôm nay
X-HubSpot-RateLimit-Daily-Reset Số giây đến khi reset ngày

Triển khai xử lý rate limit

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

Checklist triển khai sản xuất

Trước khi go-live, kiểm tra:

  • [ ] Xác thực bằng OAuth 2.0 hoặc ứng dụng riêng tư
  • [ ] Lưu token an toàn (DB mã hóa)
  • [ ] Refresh token tự động
  • [ ] Xử lý rate limit/hàng đợi request
  • [ ] Điểm cuối webhook dùng HTTPS
  • [ ] Xử lý lỗi toàn diện
  • [ ] Log toàn bộ call API
  • [ ] Giám sát sử dụng rate limit
  • [ ] Tạo runbook cho sự cố thường gặp

Các trường hợp sử dụng thực tế

Đồng bộ hóa CRM

  • Vấn đề: Nhập liệu thủ công giữa app và HubSpot
  • Giải pháp: Đồng bộ realtime qua webhook + API
  • Kết quả: Không còn nhập tay, dữ liệu chính xác 100%

Định tuyến khách hàng tiềm năng

  • Vấn đề: Phản hồi khách hàng tiềm năng chậm
  • Giải pháp: Webhook tự động phân bổ cho sales
  • Kết quả: Phản hồi trong 5 phút, tăng 40% chuyển đổi

Kết luận

API HubSpot cung cấp nền tảng tự động hóa CRM và marketing mạnh mẽ. Điểm then chốt:

  • Dùng OAuth 2.0 cho app đa tenant, ứng dụng riêng tư cho nội bộ
  • Giới hạn tốc độ theo gói (100-400 req/s)
  • Webhooks hỗ trợ đồng bộ realtime
  • Đối tượng CRM linh hoạt với custom field và liên kết
  • Apidog tối ưu kiểm thử API, cộng tác nhóm

Phần Câu hỏi thường gặp (FAQ)

Làm cách nào để xác thực với API của HubSpot?

Dùng OAuth 2.0 cho app đa tenant, ứng dụng riêng tư cho tích hợp một portal. API key đã không còn hỗ trợ.

Giới hạn tốc độ của HubSpot là gì?

Từ 100 req/s (gói miễn phí) đến 400 req/s (Doanh nghiệp), giới hạn ngày 100.000–1.000.000 request.

Làm cách nào để tạo một liên hệ trong HubSpot?

Gửi POST /crm/v3/objects/contacts với thuộc tính email, tên, họ hoặc trường custom.

Tôi có thể tạo thuộc tính tùy chỉnh không?

Có, dùng API Thuộc tính để tạo custom field cho mọi object.

Webhooks hoạt động như thế nào trong HubSpot?

Cấu hình webhook trong app settings. HubSpot sẽ POST về endpoint bạn khi event xảy ra.

Top comments (0)