🟢 HubSpot 開発者向け実践教科書 — 2026年版 Developer Edition
Chapter 3  ·  Marketing & CMS API

Marketing & CMS API
実践ガイド

Forms API・Email API・Blog API・Pages API・HubDB API の全体像と実装パターン。 マーケティング自動化・コンテンツ管理・動的データ活用を API で実現する方法を体系的に学ぶ。

Marketing Hub API
CMS Hub API
所要時間:約100分
3-1 Marketing & CMS API の全体像

Marketing Hub と CMS Hub に関連する API カテゴリを整理する。

Forms API /marketing/v3/forms Marketing
Email(Single Send)API /marketing/v3/transactional/single-email/send Marketing
Marketing Email API /marketing/v3/emails Marketing
Blog Posts API /cms/v3/blogs/posts CMS
Site Pages / Landing Pages API /cms/v3/pages/site-pages  |  /landing-pages CMS
HubDB API /cms/v3/hubdb/tables CMS
URL Mappings API /cms/v3/url-mappings CMS
スコープの注意: Marketing API と CMS API はそれぞれ異なるスコープが必要です。 Private App 作成時に contentformstransactional-email など、 使用する API に応じたスコープを付与してください。
3-2 Forms API — フォームの作成と送信データ取得

HubSpot フォームをプログラムで作成・管理し、送信データを取得・活用する。

Forms API エンドポイント
GET
/marketing/v3/forms
フォーム一覧を取得
GET
/marketing/v3/forms/{formId}
特定フォームの詳細を取得
POST
/marketing/v3/forms
新しいフォームを作成
PATCH
/marketing/v3/forms/{formId}
フォームを更新
POST
/submissions/v3/form-data/submit/{portalId}/{formGuid}
フォームにデータを送信(外部フォームからの連携)
GET
/form-integrations/v1/submissions/forms/{formGuid}
フォーム送信データを取得
Node.js — フォーム作成
import { Client } from '@hubspot/api-client'; const client = new Client({ accessToken: process.env.HUBSPOT_ACCESS_TOKEN }); // 問い合わせフォームを作成 const form = await client.marketing.forms.formsApi.create({ formType: 'hubspot', name: 'お問い合わせフォーム 2026', configuration: { language: 'ja', cloneable: false, postSubmitAction: { type: 'thank_you', value: 'お問い合わせありがとうございました。', }, }, fieldGroups: [ { fields: [ { fieldType: 'email', name: 'email', label: 'メールアドレス', required: true, }, { fieldType: 'text', name: 'firstname', label: 'お名前', required: true, }, ], }, { fields: [ { fieldType: 'textarea', name: 'message', label: 'お問い合わせ内容', required: true, }, ], }, ], }); console.log(`Form created: ${form.id}`);
Node.js — 外部フォームから HubSpot に送信
// 自社フォームから HubSpot Forms に送信する(ノーコード連携パターン) async function submitToHubSpot(formGuid, data) { const portalId = process.env.HUBSPOT_PORTAL_ID; const url = `https://api.hsforms.com/submissions/v3/integration/submit/${portalId}/${formGuid}`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ fields: [ { objectTypeId: '0-1', name: 'email', value: data.email }, { objectTypeId: '0-1', name: 'firstname', value: data.name }, { objectTypeId: '0-1', name: 'message', value: data.message }, ], context: { pageUri: data.pageUrl, pageName: data.pageName, ipAddress: data.ipAddress, }, }), }); if (!response.ok) throw new Error(`Submit failed: ${response.status}`); return await response.json(); }
Forms API と Submissions API: フォームの構造管理には /marketing/v3/forms、 フォームへのデータ送信(外部フォームからの連携)には hsforms.com の Submissions エンドポイントを使います。 後者は Private App Token なしでも送信可能ですが、スパム対策のため IP アドレスや pageUri の送信を推奨します。
3-3 Transactional Email API — 単発メール送信

購入確認・パスワードリセットなどのトランザクションメールを API から送信する。

📧 Transactional Email の要件

Transactional Email API を使うには Marketing Hub Professional 以上 が必要です。 また、送信前に HubSpot のメールツールでトランザクションメールテンプレートを作成し、 そのメール ID を指定して送信します。スコープ transactional-email が必要です。

Node.js — Single Send Email
// トランザクションメールを送信 const result = await client.marketing.transactionalApi.sendEmail({ emailId: 12345678, // HubSpot メールツールで作成した ID message: { to: 'customer@example.com', cc: ['support@mycompany.com'], replyTo: 'noreply@mycompany.com', sendId: `order-confirm-${orderId}`, // 重複送信防止の一意 ID }, contactProperties: { firstname: '太郎', email: 'customer@example.com', }, customProperties: { order_id: 'ORD-2026-001', order_amount: '¥49,800', product_name: 'Proプラン(年間)', login_url: 'https://app.example.com/login', }, }); console.log(`Status: ${result.sendResult}`); // "SENT" | "QUEUED" | "REJECTED"
Node.js — sendId による重複送信防止
// sendId が同じリクエストは重複として扱われ、再送されない // 同じ注文に対して複数回送信されても安全 const sendId = `order-${orderId}-confirm`; try { await client.marketing.transactionalApi.sendEmail({ emailId: CONFIRM_EMAIL_ID, message: { to: customerEmail, sendId }, customProperties: { order_id: orderId }, }); } catch (err) { // 409: すでに送信済み(sendId の重複) → 正常系として扱う if (err.response?.status !== 409) throw err; console.log('Email already sent (duplicate sendId). Skipping.'); }
⚠ Marketing Email と Transactional Email の違い: Marketing Email(一斉配信)はオプトアウトしたコンタクトには送信されません。 Transactional Email は商取引上必要なメール(購入確認・パスワードリセットなど)に限り、 オプトアウト済みのコンタクトにも送信されます。用途を厳守してください。
3-4 Blog Posts API — ブログ記事の管理

ブログ記事のプログラム作成・更新・公開スケジュール設定を行う。

Blog Posts API エンドポイント
GET
/cms/v3/blogs/posts
ブログ記事一覧(フィルター・ソート対応)
GET
/cms/v3/blogs/posts/{objectId}
特定記事を取得
POST
/cms/v3/blogs/posts
新しいブログ記事を作成(下書き)
PATCH
/cms/v3/blogs/posts/{objectId}
記事を更新
POST
/cms/v3/blogs/posts/{objectId}/draft/push-live
下書きを公開する
POST
/cms/v3/blogs/posts/schedule
公開日時をスケジュール設定
Node.js — ブログ記事の作成と公開
// Step 1:下書きを作成 const post = await client.cms.blogs.blogPostsApi.create({ name: 'HubSpot API 開発のベストプラクティス 2026', contentGroupId: BLOG_ID, // ブログ ID(HubSpot 管理画面で確認) slug: 'hubspot-api-best-practices-2026', metaDescription: 'HubSpot API を使った開発の最新ベストプラクティスを解説。', postBody: ` <h2>はじめに</h2> <p>HubSpot API v3 では...</p> `, tagIds: [TAG_ID_1, TAG_ID_2], featuredImage: 'https://example.com/og-image.png', featuredImageAltText: 'HubSpot API 開発', publishDate: '2026-04-01T09:00:00.000Z', currentState: 'DRAFT', }); // Step 2:即時公開する場合 await client.cms.blogs.blogPostsApi.pushLiveDraft(post.id); // Step 2(別パターン):日時指定で公開スケジュール await fetch( `https://api.hubapi.com/cms/v3/blogs/posts/schedule`, { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ id: post.id, publishDate: '2026-04-01T09:00:00.000Z', }), } );
Node.js — ブログ記事の一覧取得とフィルター
// 公開済みの記事のみ取得(直近30件) const posts = await client.cms.blogs.blogPostsApi.getPage( undefined, // after(ページネーション) 30, // limit undefined, undefined, undefined, 'PUBLISHED', // state フィルター undefined, undefined, undefined, undefined, 'publishDate', // sort 'DESCENDING' ); console.log(posts.results.map(p => ({ id: p.id, name: p.name, url: p.url })));
3-5 Pages API — サイトページ・ランディングページの管理

CMS Hub のページをプログラムで作成・複製・公開する。

📄 Site Pages

通常のウェブサイトページ。
エンドポイント:/cms/v3/pages/site-pages
用途:会社概要・製品ページ・FAQ など

🎯 Landing Pages

マーケティング用ランディングページ。
エンドポイント:/cms/v3/pages/landing-pages
用途:キャンペーン・ホワイトペーパーDLなど

Node.js — ランディングページの作成と公開
// ランディングページを作成(下書き状態) const page = await fetch( 'https://api.hubapi.com/cms/v3/pages/landing-pages', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ name: '春キャンペーン 2026 LP', slug: 'spring-campaign-2026', templatePath: '@hubspot/growth/templates/landing-page.html', headHtml: '<meta name="description" content="春キャンペーン特集">', metaDescription: '春キャンペーン特集ページ', currentState: 'DRAFT', }), } ).then(r => r.json()); // 下書きを即時公開 await fetch( `https://api.hubapi.com/cms/v3/pages/landing-pages/${page.id}/draft/push-live`, { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}` }, } );
Node.js — ページの複製(テンプレートから量産)
// 既存ページを複製して新しいキャンペーンページを量産するパターン async function clonePage(sourcePageId, newName, newSlug) { const res = await fetch( `https://api.hubapi.com/cms/v3/pages/landing-pages/${sourcePageId}/clone`, { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ name: newName }), } ); const cloned = await res.json(); // スラッグを更新 await fetch( `https://api.hubapi.com/cms/v3/pages/landing-pages/${cloned.id}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ slug: newSlug }), } ); return cloned; }
3-6 HubDB API — 動的テーブルデータの管理

HubDB はスプレッドシート感覚で使えるデータベース。CMS ページに動的コンテンツを埋め込む際に活用する。

🗄 HubDB のユースケース

HubDB は「CMS ページで動的なデータを表示したい」ときに使います。 例えば店舗一覧ページ・チームメンバー紹介・料金表・FAQなど、 構造化されたデータを HubDB テーブルに格納し、HubL テンプレートから呼び出して表示します。 API からも読み書きできるため、外部システムとの同期にも使えます。

HubDB API エンドポイント
GET
/cms/v3/hubdb/tables
テーブル一覧を取得
POST
/cms/v3/hubdb/tables
新しいテーブルを作成
GET
/cms/v3/hubdb/tables/{tableIdOrName}/rows
テーブルの行データを取得
POST
/cms/v3/hubdb/tables/{tableIdOrName}/rows
行を追加
PATCH
/cms/v3/hubdb/tables/{tableIdOrName}/rows/{rowId}/draft
行を更新(下書き)
POST
/cms/v3/hubdb/tables/{tableIdOrName}/draft/publish
下書きを公開(テーブル全体)
Node.js — HubDB テーブル作成
// 店舗情報テーブルを作成 const table = await client.cms.hubdb.tablesApi.createTable({ name: 'store_locations', label: '店舗一覧', useForPages: true, // ページテンプレートとして使用 columns: [ { name: 'store_name', label: '店舗名', type: 'TEXT' }, { name: 'address', label: '住所', type: 'TEXT' }, { name: 'phone', label: '電話番号', type: 'TEXT' }, { name: 'prefecture', label: '都道府県', type: 'SELECT', options: [ { name: '東京都', type: 'option', order: 1 }, { name: '大阪府', type: 'option', order: 2 }, { name: '愛知県', type: 'option', order: 3 }, ], }, { name: 'latitude', label: '緯度', type: 'NUMBER' }, { name: 'longitude', label: '経度', type: 'NUMBER' }, { name: 'is_open', label: '営業中', type: 'BOOL' }, ], });
Node.js — 行の追加と公開
// 行データを追加 await client.cms.hubdb.rowsApi.createTableRow(table.id, { values: { store_name: '渋谷店', address: '東京都渋谷区渋谷1-1-1', phone: '03-1234-5678', prefecture: { name: '東京都' }, latitude: 35.6580, longitude: 139.7016, is_open: true, }, }); // 変更を公開(draft → live) await client.cms.hubdb.tablesApi.publishDraftTable(table.id);
Node.js — HubDB データの取得とフィルター
// 営業中の店舗を都道府県でフィルターして取得 const rows = await client.cms.hubdb.rowsApi.getTableRows( 'store_locations', // テーブル名 undefined, // sort undefined, // after 100, // limit undefined, undefined, 'is_open=true', // フィルター ); console.log(rows.results.map(r => r.values)); // または REST API 直接呼び出し(より柔軟なフィルタリング) const response = await fetch( 'https://api.hubapi.com/cms/v3/hubdb/tables/store_locations/rows?prefecture__contains=東京&is_open=true&limit=50', { headers: { 'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}` } } ); const data = await response.json();
HubDB の下書き管理: HubDB はライブ版と下書き版の2つの状態を持ちます。 行を追加・更新した後は必ず publishDraftTable() を実行して公開してください。 公開しないと CMS ページには反映されません。
3-7 URL Mappings API — リダイレクト管理

旧 URL から新 URL へのリダイレクトをプログラムで一括管理する。サイトリニューアル時に特に有用。

Node.js — リダイレクト一括登録
// CSVや配列から大量のリダイレクトを一括登録する const redirects = [ { routePrefix: '/old-blog/article-1', destination: '/blog/new-article-1', redirectStyle: 301 }, { routePrefix: '/old-about', destination: '/about-us', redirectStyle: 301 }, { routePrefix: '/campaign-2025', destination: '/campaign-2026', redirectStyle: 302 }, ]; for (const redirect of redirects) { await fetch('https://api.hubapi.com/cms/v3/url-mappings', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ routePrefix: redirect.routePrefix, destination: redirect.destination, redirectStyle: redirect.redirectStyle, isOnlyAfterNotFound: false, isMatchQueryString: false, }), }); // レート制限対策 await new Promise(r => setTimeout(r, 100)); } console.log(`${redirects.length} redirects registered.`);
3-8 実践パターン:外部システムと HubSpot の同期

外部データを HubDB や Blog API に定期同期する実用的なパターンを学ぶ。

🔄 同期パターンの例

社内の商品データベース(MySQL など)の情報を毎日 HubDB に同期し、 HubSpot の CMS ページで常に最新の商品情報を表示する。 同期処理は Node.js スクリプト + GitHub Actions のスケジュール実行で実装できます。

Node.js — HubDB への差分同期スクリプト
/** * 外部データを HubDB に差分同期する * 1. 外部データを取得 * 2. HubDB の現在データと比較 * 3. 追加・更新・削除を実行 * 4. publish して公開 */ async function syncToHubDB(tableId, externalData) { // 既存の行を全取得 const existing = await client.cms.hubdb.rowsApi.getTableRows(tableId, undefined, undefined, 1000); const existingMap = new Map(existing.results.map(r => [r.values.external_id, r])); let added = 0, updated = 0, deleted = 0; // 追加・更新 for (const item of externalData) { const existing_row = existingMap.get(item.id); if (!existing_row) { await client.cms.hubdb.rowsApi.createTableRow(tableId, { values: { external_id: item.id, name: item.name, price: item.price }, }); added++; } else if (existing_row.values.price !== item.price) { await client.cms.hubdb.rowsApi.updateDraftTableRow(tableId, existing_row.id, { values: { price: item.price }, }); updated++; } existingMap.delete(item.id); } // 削除(外部データに存在しなくなった行) for (const [, row] of existingMap) { await client.cms.hubdb.rowsApi.purgeDraftTableRow(tableId, row.id); deleted++; } // 公開 await client.cms.hubdb.tablesApi.publishDraftTable(tableId); console.log(`Sync done: +${added} / ~${updated} / -${deleted}`); }
.github/workflows/hubdb-sync.yml
name: Sync Products to HubDB on: schedule: - cron: '0 2 * * *' # 毎日 02:00 UTC(JST 11:00)に実行 workflow_dispatch: # 手動実行も可能 jobs: sync: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - run: npm ci - name: Run sync env: HUBSPOT_ACCESS_TOKEN: ${{ secrets.HUBSPOT_ACCESS_TOKEN }} DB_CONNECTION_STRING: ${{ secrets.DB_CONNECTION_STRING }} run: node scripts/sync-products.js
3-9 この章のまとめ

次章(カスタムオブジェクト & スキーマ設計)に進む前に確認する。

✅ Chapter 3 チェックリスト

  • Marketing API と CMS API のカテゴリ分けとスコープ要件を理解した
  • Forms API でフォームをプログラム作成できる
  • 外部フォームから HubSpot Forms にデータ送信できる(Submissions API)
  • Transactional Email API でトランザクションメールを送信できる
  • sendId による重複送信防止を実装できる
  • Blog Posts API で記事の作成・更新・公開・スケジュール設定ができる
  • Pages API でランディングページの作成・複製・公開ができる
  • HubDB のテーブル構造(ライブ版/下書き版)を理解した
  • HubDB テーブルの作成・行追加・公開を実装できる
  • 外部データを HubDB に差分同期するスクリプトを理解した
  • URL Mappings API でリダイレクトを一括登録できる
  • GitHub Actions のスケジュール実行で定期同期を自動化できる
次章(Chapter 4)について: カスタムオブジェクトとスキーマ設計を学びます。標準オブジェクトでは表現できないビジネスデータ構造を カスタムオブジェクトとして設計し、プロパティ型・アソシエーション・Enterprise 専用機能まで解説します。