Chapter 3 · Marketing & CMS API
Marketing & CMS API
practical guide
The overall picture and implementation patterns of Forms API, Email API, Blog API, Pages API, and HubDB API.
Systematically learn how to implement marketing automation, content management, and dynamic data utilization using APIs.
3-1 Overview of Marketing & CMS API
Organize API categories related to Marketing Hub and CMS Hub.
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
Scope note:
The Marketing API and CMS API each require different scopes.
When creating a Private App content・forms・transactional-email etc.,
Please assign a scope according to the API you use.
3-2 Forms API — Create form and get submitted data
Programmatically create and manage HubSpot forms, capture and leverage submission data.
Forms API endpoint
GET
/marketing/v3/forms
Get form list
GET
/marketing/v3/forms/{formId}
Get specific form details
POST
/marketing/v3/forms
create new form
PATCH
/marketing/v3/forms/{formId}
Update form
POST
/submissions/v3/form-data/submit/{portalId}/{formGuid}
Send data to form (link from external form)
GET
/form-integrations/v1/submissions/forms/{formGuid}
Get form submission data
Node.js — form creation
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:
'Contact Form 2026',
configuration: {
language:
'ja',
cloneable:
false,
postSubmitAction: {
type:
'thank_you',
value:
'Thank you for contacting us. ',
},
},
fieldGroups: [
{
fields: [
{
fieldType:
'email',
name:
'email',
label:
'email address',
required:
true,
},
{
fieldType:
'text',
name:
'firstname',
label:
'Name',
required:
true,
},
],
},
{
fields: [
{
fieldType:
'textarea',
name:
'message',
label:
'Inquiry details',
required:
true,
},
],
},
],
});
console.log(
`Form created: ${form.id}`);
Node.js — Send to HubSpot from external 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 and Submissions API:
of the formstructure managementfor /marketing/v3/forms,
to formdata transmission(Linking from external form) hsforms.com Use the Submissions endpoint of .
Although the latter can be sent without a Private App Token, we recommend sending the IP address or pageUri to prevent spam.
3-3 Transactional Email API — Single email sending
Send transaction emails such as purchase confirmations and password resets from the API.
📧 Transactional Email Requirements
How to use the Transactional Email API Marketing Hub Professional or higher is required.
You can also use HubSpot's email tools before sending.Create a transactional email templateAnd
Specify that email ID and send. scope transactional-email is required.
Node.js — Single Send Email
const result =
await client.marketing.transactionalApi.sendEmail({
emailId:
12345678,
message: {
to:
'customer@example.com',
cc: [
'support@mycompany.com'],
replyTo:
'noreply@mycompany.com',
sendId:
`order-confirm-${orderId}`,
},
contactProperties: {
firstname:
'Taro',
email:
'customer@example.com',
},
customProperties: {
order_id:
'ORD-2026-001',
order_amount:
'¥49,800',
product_name:
'Pro Plan (Annual)',
login_url:
'https://app.example.com/login',
},
});
console.log(
`Status: ${result.sendResult}`);
Node.js — Prevent duplicate sending with 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) {
if (err.response?.status !==
409)
throw err;
console.log(
'Email already sent (duplicate sendId). Skipping.');
}
⚠ Difference between Marketing Email and Transactional Email:
Marketing emails (broadcast) will not be sent to contacts who have opted out.
Transactional EmailEmail necessary for commercial transactions(Purchase confirmation, password reset, etc.) only.
It will also be sent to contacts who have opted out. Please strictly follow the intended use.
3-4 Blog Posts API — Blog article management
Create programs, update, and publish schedules for blog articles.
Blog Posts API endpoint
GET
/cms/v3/blogs/posts
Blog article list (filter/sort supported)
GET
/cms/v3/blogs/posts/{objectId}
Get specific article
POST
/cms/v3/blogs/posts
Create a new blog post (draft)
PATCH
/cms/v3/blogs/posts/{objectId}
Update article
POST
/cms/v3/blogs/posts/{objectId}/draft/push-live
Publish your draft
POST
/cms/v3/blogs/posts/schedule
Schedule a publishing date and time
Node.js — Create and publish blog posts
const post =
await client.cms.blogs.blogPostsApi.create({
name:
'HubSpot API Development Best Practices 2026',
contentGroupId:
BLOG_ID,
slug:
'hubspot-api-best-practices-2026',
metaDescription:
'Explaining the latest best practices for developing with the HubSpot API. ',
postBody:
`
<h2>Introduction</h2>
<p>With HubSpot API v3...</p>
`,
tagIds: [
TAG_ID_1,
TAG_ID_2],
featuredImage:
'https://example.com/og-image.png',
featuredImageAltText:
'HubSpot API development',
publishDate:
'2026-04-01T09:00:00.000Z',
currentState:
'DRAFT',
});
await client.cms.blogs.blogPostsApi.pushLiveDraft(post.id);
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 — List and filter blog articles
const posts =
await client.cms.blogs.blogPostsApi.getPage(
undefined,
30,
undefined,
undefined,
undefined,
'PUBLISHED',
undefined,
undefined,
undefined,
undefined,
'publishDate',
'DESCENDING'
);
console.log(posts.results.map(p => ({ id: p.id, name: p.name, url: p.url })));
3-5 Pages API — Site page/landing page management
Create, clone, and publish CMS Hub pages programmatically.
📄 Site Pages
Regular website page.
Endpoint:/cms/v3/pages/site-pages
Usage: Company profile, product page, FAQ, etc.
🎯 Landing Pages
Marketing landing page.
Endpoint:/cms/v3/pages/landing-pages
Purpose: Campaign, white paper DL, etc.
Node.js — Creating and publishing landing pages
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:
'Spring Campaign 2026 LP',
slug:
'spring-campaign-2026',
templatePath:
'@hubspot/growth/templates/landing-page.html',
headHtml:
'<meta name="description" content="Spring Campaign Special">',
metaDescription:
'Spring campaign special page',
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 — Page duplication (mass production from template)
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 — Dynamic table data management
HubDB is a database that can be used like a spreadsheet. Used when embedding dynamic content in CMS pages.
🗄 HubDB use cases
HubDB is used when you want to display dynamic data on a CMS page.
for exampleStore list page, team member introduction, price list, FAQetc.,
Store structured data in HubDB tables and call and display it from HubL templates.
It can also be read and written from the API, so it can also be used to synchronize with external systems.
HubDB API endpoint
GET
/cms/v3/hubdb/tables
Get table list
POST
/cms/v3/hubdb/tables
create new table
GET
/cms/v3/hubdb/tables/{tableIdOrName}/rows
Get table row data
POST
/cms/v3/hubdb/tables/{tableIdOrName}/rows
add row
PATCH
/cms/v3/hubdb/tables/{tableIdOrName}/rows/{rowId}/draft
Update row (draft)
POST
/cms/v3/hubdb/tables/{tableIdOrName}/draft/publish
Publish draft (entire table)
Node.js — HubDB table creation
const table =
await client.cms.hubdb.tablesApi.createTable({
name:
'store_locations',
label:
'List of stores',
useForPages:
true,
columns: [
{ name:
'store_name', label:
'Store name', type:
'TEXT' },
{ name:
'address', label:
'address', type:
'TEXT' },
{ name:
'phone', label:
'telephone number', type:
'TEXT' },
{ name:
'prefecture', label:
'prefectures', type:
'SELECT',
options: [
{ name:
'Tokyo', type:
'option', order:
1 },
{ name:
'Osaka Prefecture', type:
'option', order:
2 },
{ name:
'Aichi prefecture', type:
'option', order:
3 },
],
},
{ name:
'latitude', label:
'latitude', type:
'NUMBER' },
{ name:
'longitude', label:
'longitude', type:
'NUMBER' },
{ name:
'is_open', label:
'Open', type:
'BOOL' },
],
});
Node.js — Adding and publishing rows
await client.cms.hubdb.rowsApi.createTableRow(table.id, {
values: {
store_name:
'Shibuya store',
address:
'1-1-1 Shibuya, Shibuya-ku, Tokyo',
phone:
'03-1234-5678',
prefecture: { name:
'Tokyo' },
latitude:
35.6580,
longitude:
139.7016,
is_open:
true,
},
});
await client.cms.hubdb.tablesApi.publishDraftTable(table.id);
Node.js — HubDB data retrieval and filtering
const rows =
await client.cms.hubdb.rowsApi.getTableRows(
'store_locations',
undefined,
undefined,
100,
undefined,
undefined,
'is_open=true',
);
console.log(rows.results.map(r => r.values));
const response =
await fetch(
'https://api.hubapi.com/cms/v3/hubdb/tables/store_locations/rows?prefecture__contains=Tokyo&is_open=true&limit=50',
{ headers: {
'Authorization':
`Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}` } }
);
const data =
await response.json();
HubDB draft management:
HubDB isLive version and draft versionIt has two states.
After adding or updating a row, be sure to publishDraftTable() Please run and publish.
If you do not publish it, it will not be reflected on the CMS page.
3-7 URL Mappings API — Redirect management
Programmatically manage redirects from old URLs to new URLs. Especially useful when renewing a site.
Node.js — Bulk redirect registration
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 Practical pattern: Syncing external systems with HubSpot
Learn practical patterns for periodically syncing external data to HubDB and Blog API.
🔄 Examples of sync patterns
Information from internal product databases (MySQL, etc.)Sync daily to HubDBAnd
Always see up-to-date product information on HubSpot's CMS pages.
Synchronization can be implemented using Node.js scripts + scheduled execution of GitHub Actions.
Node.js — Delta sync script to HubDB
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 * * *'
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 Summary of this chapter
Review before proceeding to the next chapter (Custom Object & Schema Design).
✅ Chapter 3 Checklist
- Understand the categorization and scoping requirements for Marketing API and CMS API
- Create forms programmatically with the Forms API
- You can submit data from external forms to HubSpot Forms (Submissions API)
- Transactional Email API lets you send transactional emails
- Can implement duplicate sending prevention using sendId
- Blog Posts API allows you to create, update, publish, and schedule articles.
- You can create, duplicate, and publish landing pages using the Pages API.
- Understood the table structure of HubDB (live version/draft version)
- You can create, add rows, and publish HubDB tables.
- Understand the script to incrementally sync external data to HubDB
- You can register redirects in bulk using the URL Mappings API.
- You can automate periodic synchronization by scheduling GitHub Actions.
About the next chapter (Chapter 4):
Learn custom object and schema design. Business data structures that cannot be expressed using standard objects
We will design it as a custom object and explain property types, associations, and Enterprise-specific functions.