2-1 CRM API の全体像
HubSpot CRM API v3 は Object ベースの RESTful API。まず構造を把握する。
🏗 CRM API の基本構造
HubSpot CRM API はオブジェクト(Object)単位で設計されています。
Contacts・Companies・Deals・Tickets などの標準オブジェクトに加え、カスタムオブジェクトも同じ API パターンで操作できます。
各オブジェクトには「プロパティ(Properties)」「アソシエーション(Associations)」「エンゲージメント(Engagements)」が紐づきます。
| オブジェクト | API パス | 用途 |
| Contacts | /crm/v3/objects/contacts | 見込み客・顧客の個人情報 |
| Companies | /crm/v3/objects/companies | 取引先企業情報 |
| Deals | /crm/v3/objects/deals | 商談・案件 |
| Tickets | /crm/v3/objects/tickets | サポートチケット |
| Products | /crm/v3/objects/products | 商品・製品カタログ |
| Line Items | /crm/v3/objects/line_items | 商談に紐づく明細行 |
| Quotes | /crm/v3/objects/quotes | 見積書 |
| Custom Objects | /crm/v3/objects/{objectType} | カスタムオブジェクト(4章で詳説) |
ベース URL:
すべての CRM API リクエストのベース URL は https://api.hubapi.com です。
認証ヘッダーは Authorization: Bearer {ACCESS_TOKEN} を使用します。
2-2 Objects API — CRUD 操作
コンタクトを例に、作成・取得・更新・削除の基本操作をマスターする。
Contacts エンドポイント一覧
GET
/crm/v3/objects/contacts
コンタクト一覧を取得(ページネーション対応)
GET
/crm/v3/objects/contacts/{contactId}
特定コンタクトを ID で取得
POST
/crm/v3/objects/contacts
新しいコンタクトを作成
PATCH
/crm/v3/objects/contacts/{contactId}
コンタクトのプロパティを更新
DELETE
/crm/v3/objects/contacts/{contactId}
コンタクトをアーカイブ(論理削除)
Node.js — コンタクト CRUD
import { Client }
from '@hubspot/api-client';
const client =
new Client({ accessToken: process.env.HUBSPOT_ACCESS_TOKEN });
const newContact =
await client.crm.contacts.basicApi.create({
properties: {
email:
'taro@example.com',
firstname:
'太郎',
lastname:
'山田',
phone:
'090-1234-5678',
company:
'株式会社サンプル',
},
});
console.log(
'Created:', newContact.id);
const contact =
await client.crm.contacts.basicApi.getById(
newContact.id,
[
'email',
'firstname',
'lastname',
'hs_lead_status']
);
await client.crm.contacts.basicApi.update(newContact.id, {
properties: {
hs_lead_status:
'IN_PROGRESS',
lifecyclestage:
'opportunity',
},
});
await client.crm.contacts.basicApi.archive(newContact.id);
Node.js — 一覧取得とページネーション
async function getAllContacts() {
const allContacts = [];
let after = undefined;
do {
const page =
await client.crm.contacts.basicApi.getPage(
100,
after,
[
'email',
'firstname',
'lastname',
'createdate']
);
allContacts.push(...page.results);
after = page.paging?.next?.after;
if (after)
await new Promise(r => setTimeout(r,
100));
}
while (after);
return allContacts;
}
アーカイブ vs 完全削除:
archive() は論理削除(アーカイブ)で、30日間は復元可能です。
完全削除(GDPR 対応など)が必要な場合は gdprDeleteApi.purge() を使用しますが、復元不可のため注意してください。
2-3 Search API — 高度な絞り込み検索
フィルター・ソート・全文検索を組み合わせて CRM データを柔軟に検索する。
🔍 Search API の特徴
Search API は POST /crm/v3/objects/{objectType}/search エンドポイントで、
複数のフィルターグループ(OR 条件)とフィルター(AND 条件)を組み合わせた複雑な絞り込みが可能です。
1リクエストで最大 10,000件まで取得でき、ページネーションにも対応しています。
| 演算子 | 意味 | 例 |
EQ | 等しい | lifecyclestage = "customer" |
NEQ | 等しくない | hs_lead_status ≠ "UNQUALIFIED" |
GT / GTE | より大きい / 以上 | createdate > 特定日時 |
LT / LTE | より小さい / 以下 | amount < 100000 |
CONTAINS_TOKEN | トークンを含む(部分一致) | email contains "@example.com" |
IN | リスト内のいずれか | country IN ["JP", "US", "UK"] |
NOT_IN | リスト内のいずれでもない | lifecyclestage NOT IN ["other"] |
HAS_PROPERTY | プロパティが存在する | phone が設定されている |
NOT_HAS_PROPERTY | プロパティが存在しない | email が未設定 |
BETWEEN | 範囲内 | amount BETWEEN 10000 AND 50000 |
Node.js — Search API 実装例
const thirtyDaysAgo = Date.now() - (
30 *
24 *
60 *
60 *
1000);
const searchResult =
await client.crm.contacts.searchApi.doSearch({
filterGroups: [
{
filters: [
{
propertyName:
'lifecyclestage',
operator:
'EQ',
value:
'customer',
},
{
propertyName:
'createdate',
operator:
'GTE',
value: thirtyDaysAgo.toString(),
},
],
},
],
properties: [
'email',
'firstname',
'lastname',
'createdate'],
sorts: [{ propertyName:
'createdate', direction:
'DESCENDING' }],
limit:
100,
after:
0,
});
console.log(
`Total: ${searchResult.total}`);
console.log(searchResult.results);
Node.js — OR 条件(複数フィルターグループ)
const result =
await client.crm.contacts.searchApi.doSearch({
filterGroups: [
{
filters: [{ propertyName:
'lifecyclestage', operator:
'EQ', value:
'lead' }],
},
{
filters: [{ propertyName:
'lifecyclestage', operator:
'EQ', value:
'opportunity' }],
},
],
properties: [
'email',
'lifecyclestage',
'hubspot_owner_id'],
limit:
200,
});
Node.js — Search API で全件取得(ページネーション)
async function searchAll(objectType, filterGroups, properties = []) {
const results = [];
let after =
0;
while (true) {
const page =
await client.crm[objectType].searchApi.doSearch({
filterGroups,
properties,
limit:
100,
after,
});
results.push(...page.results);
if (!page.paging?.next?.after)
break;
after = page.paging.next.after;
await new Promise(r => setTimeout(r,
200));
}
return results;
}
const allDeals =
await searchAll(
'deals', [
{ filters: [{ propertyName:
'dealstage', operator:
'EQ', value:
'closedwon' }] },
], [
'dealname',
'amount',
'closedate']);
⚠ Search API の上限:
1回の検索で取得できるレコード数の上限は 10,000件です。10,000件を超えるデータを取得する場合は、
日付範囲などでデータを分割して複数回リクエストするか、Exports API の利用を検討してください。
2-4 Associations API — オブジェクト間の関連付け
コンタクト・会社・商談などのオブジェクトを相互に関連付け、CRM の関係性を表現する。
🔗 Associations の基本概念
HubSpot では異なるオブジェクト間の関係を「アソシエーション」として管理します。
例えば「コンタクト → 会社」「コンタクト → 商談」「商談 → 会社」などが代表的な関係です。
v3 API では アソシエーションタイプ を指定することで、関係の種類(主担当・関係者・意思決定者など)も表現できます。
| よく使うアソシエーション | fromObject | toObject | typeId |
| コンタクト → 会社(主所属) | contacts | companies | 1 |
| 会社 → コンタクト | companies | contacts | 2 |
| コンタクト → 商談 | contacts | deals | 4 |
| 商談 → コンタクト | deals | contacts | 3 |
| 会社 → 商談 | companies | deals | 6 |
| 商談 → 会社 | deals | companies | 5 |
| コンタクト → チケット | contacts | tickets | 16 |
Node.js — Associations CRUD
await client.crm.associations.v4.basicApi.create(
'contacts',
contactId,
'companies',
companyId,
[{ associationCategory:
'HUBSPOT_DEFINED', associationTypeId:
1 }]
);
const associations =
await client.crm.associations.v4.basicApi.getPage(
'contacts',
contactId,
'companies'
);
console.log(associations.results.map(a => a.toObjectId));
await client.crm.associations.v4.basicApi.archive(
'contacts', contactId,
'companies', companyId
);
Node.js — オブジェクト作成と同時に関連付け
const newDeal =
await client.crm.deals.basicApi.create({
properties: {
dealname:
'エンタープライズ契約 2026',
amount:
'5000000',
dealstage:
'appointmentscheduled',
pipeline:
'default',
closedate:
'2026-06-30',
},
associations: [
{
to: { id: contactId },
types: [{ associationCategory:
'HUBSPOT_DEFINED', associationTypeId:
3 }],
},
{
to: { id: companyId },
types: [{ associationCategory:
'HUBSPOT_DEFINED', associationTypeId:
5 }],
},
],
});
2-5 Batch API — 大量データの効率処理
複数レコードを1リクエストでまとめて操作し、API コール数とレート制限への負荷を削減する。
⚡ Batch API の特徴
Batch API は1リクエストで最大 100件のレコードをまとめて操作できます。
1件ずつ操作するより最大100倍効率的で、レート制限(100req/10sec)を大幅に緩和できます。
作成・読み取り・更新・削除のすべての操作に対応しています。
Node.js — Batch 作成
const batchCreateResult =
await client.crm.contacts.batchApi.create({
inputs: [
{ properties: { email:
'user1@example.com', firstname:
'ユーザー1' } },
{ properties: { email:
'user2@example.com', firstname:
'ユーザー2' } },
{ properties: { email:
'user3@example.com', firstname:
'ユーザー3' } },
],
});
console.log(
`Created ${batchCreateResult.results.length} contacts`);
Node.js — Batch 更新
const batchUpdateResult =
await client.crm.contacts.batchApi.update({
inputs: [
{ id:
'101', properties: { lifecyclestage:
'customer' } },
{ id:
'102', properties: { lifecyclestage:
'customer' } },
{ id:
'103', properties: { hs_lead_status:
'UNQUALIFIED' } },
],
});
Node.js — 大量データを Batch で処理するユーティリティ
async function processBatch(items, batchFn, chunkSize =
100) {
const results = [];
for (
let i =
0; i < items.length; i += chunkSize) {
const chunk = items.slice(i, i + chunkSize);
const result =
await batchFn(chunk);
results.push(...result.results);
if (i + chunkSize < items.length) {
await new Promise(r => setTimeout(r,
200));
}
}
return results;
}
const updates = contactIds.map(id => ({
id,
properties: { custom_sync_status:
'synced' },
}));
await processBatch(updates, (chunk) =>
client.crm.contacts.batchApi.update({ inputs: chunk })
);
2-6 Properties API — カスタムプロパティの管理
プロパティの一覧取得・作成・更新を API で管理する。
| プロパティ型 | fieldType | 用途 |
| string | text / textarea | テキスト入力 |
| number | number | 数値(金額・スコアなど) |
| enumeration | select / radio / checkbox | 選択式。options リストが必要 |
| date | date | 日付(YYYY-MM-DD) |
| datetime | date | 日時(Unix ミリ秒) |
| bool | booleancheckbox | True / False |
Node.js — カスタムプロパティの作成
const newProperty =
await client.crm.properties.coreApi.create(
'contacts',
{
name:
'custom_score',
label:
'カスタムスコア',
type:
'number',
fieldType:
'number',
groupName:
'contactinformation',
description:
'外部システムから同期したスコア値',
displayOrder:
-1,
hasUniqueValue:
false,
}
);
const enumProperty =
await client.crm.properties.coreApi.create(
'contacts',
{
name:
'customer_tier',
label:
'顧客ティア',
type:
'enumeration',
fieldType:
'select',
groupName:
'contactinformation',
options: [
{ label:
'プラチナ', value:
'platinum', displayOrder:
1 },
{ label:
'ゴールド', value:
'gold', displayOrder:
2 },
{ label:
'シルバー', value:
'silver', displayOrder:
3 },
],
}
);
2-7 レート制限の実践的な対処
429 エラーを防ぎ、大量データ処理を安全に行うためのパターンを学ぶ。
📊 レート制限の仕様
10秒あたり: 100リクエスト
1日あたり: プランに依存
Burst: 短時間の急増は 429 を返す
Batch API: 1req = 最大100件分
✅ 推奨対策
Batch API 優先: 単件操作を避ける
Exponential Backoff: 429時にリトライ
キュー処理: 同時実行数を制限
オフピーク処理: 夜間バッチ実行
Node.js — レート制限対応ラッパー(本番推奨)
import pLimit
from 'p-limit';
const limit = pLimit(
5);
async function safeApiCall(fn, maxRetries =
4) {
for (
let attempt =
0; attempt < maxRetries; attempt++) {
try {
return await fn();
}
catch (err) {
const status = err.response?.status;
const isRetryable = status ===
429 || status ===
502 || status ===
503;
if (isRetryable && attempt < maxRetries -
1) {
const retryAfter = err.response?.headers[
'retry-after'];
const wait = retryAfter
? parseInt(retryAfter) *
1000
: Math.pow(
2, attempt) *
1000;
console.warn(
`Rate limited. Retrying in ${wait}ms (attempt ${attempt + 1})`);
await new Promise(r => setTimeout(r, wait));
}
else {
throw err;
}
}
}
}
const promises = contactIds.map(id =>
limit(() => safeApiCall(() =>
client.crm.contacts.basicApi.getById(id, [
'email',
'firstname'])
))
);
const contacts =
await Promise.all(promises);
2-8 Timeline API — カスタムイベントの記録
外部システムのイベント(購入・ログイン・操作履歴など)を HubSpot のタイムラインに記録する。
📅 Timeline API のユースケース
外部システムで起きたアクション(ECサイトでの購入・SaaSへのログイン・アプリ内操作など)を
HubSpot のコンタクトタイムラインに記録することで、営業・サポートチームがすべての顧客行動を
HubSpot だけで確認できるようになります。
Node.js — Timeline イベントの作成
const template =
await client.crm.timeline.templatesApi.create(appId, {
name:
'商品購入',
headerTemplate:
'{{contactName}} が {{productName}} を購入しました',
detailTemplate:
'注文 ID: {{orderId}} / 金額: ¥{{amount}}',
tokens: [
{ name:
'productName', type:
'string', label:
'商品名' },
{ name:
'orderId', type:
'string', label: '注文 ID' },
{ name:
'amount', type:
'number', label:
'金額' },
],
objectType:
'CONTACT',
});
await client.crm.timeline.eventsApi.create({
eventTemplateId: template.id,
objectId: contactId,
tokens: {
productName:
'Proプラン',
orderId:
'ORD-2026-001',
amount:
49800,
},
timestamp:
new Date().toISOString(),
});
2-9 この章のまとめ
次章(Marketing & CMS API)に進む前に確認する。
✅ Chapter 2 チェックリスト
- CRM API v3 のオブジェクト構造(Contacts / Companies / Deals など)を理解した
- Objects API で CRUD 操作(作成・取得・更新・削除)を実装できる
- ページネーションを使って全レコードを取得できる
- Search API のフィルター・ソート・OR 条件を組み合わせた検索を実装できる
- Search API の10,000件上限と回避策を理解した
- Associations API でオブジェクト間の関連付けを作成・削除できる
- オブジェクト作成時に associations を同時に指定できる
- Batch API で100件単位の一括操作を実装できる
- 大量データを chunk 処理するユーティリティを実装できる
- レート制限対応(exponential backoff + p-limit)を理解した
- Properties API でカスタムプロパティを作成できる
- Timeline API で外部イベントを HubSpot に記録できる
次章(Chapter 3)について:
Marketing Hub と CMS に関連する API を学びます。Forms API・Email API・Blog API・Pages API・HubDB API の実装パターンを、
マーケティング自動化の観点から解説します。