██╗ ██╗██████╗ ██╗ ██╗██║ ██║██╔═══╝ ╚██╗██╔╝███████║██████╗ █████╗ ╚███╔╝ ██╔══██║╚═══██║ ╚════╝ ██╔██╗ ██║ ██║██████║ ██╔╝ ██╗╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝

The developer toolkit for HubSpot — build syncs, UI extensions, agent tools, workflow actions, triggers, and a runtime you own.
One install. The whole toolkit.

$ npm i -g @hs-x/cli
or read the docs not a developer?
works with via mcp 15-minute AI build
BUILD

Four things you can build for HubSpot. One project, one deploy.

Sync any system into HubSpot, and keep it current.

Point a Worker at Airtable, Postgres, Snowflake, or any API. Its records land in HubSpot as contacts, companies, or any object you choose, and refresh on a schedule. Cursors, duplicate matching, retries, and drift detection are handled for you. You write the fetch.

airtableSync · live
Rows synced247 / 247
Drift0 · in sync
Scheduleevery 5 m
CursorrecX47 + 14 s
airtableSync.tsSDK · v0.4
import { defineSource, defineWorker } from "@hs-x/sdk";

const airtableContacts = defineSource({
  name: "airtableContacts",
  auth: { type: "bearer", token: process.env.AIRTABLE_TOKEN },
  async fetch({ cursor, http }) {
    const res = await http.get("https://api.airtable.com/v0/appXYZ/Contacts", {
      query: { pageSize: 100, offset: cursor },
    });
    return {
      cursor: res.body.offset,
      rows: res.body.records.map(r => ({
        key: r.fields.Email,
        data: {
          email: r.fields.Email,
          lifecycle_stage: r.fields.Stage,
          annual_revenue: r.fields.ARR,
          owner: r.fields.OwnerEmail,
        },
      })),
    };
  },
});

const worker = defineWorker("contacts");

worker.sync(airtableContacts, {
  into: "contacts",
  schedule: "5m",
  schema: {
    email: "email",
    lifecycle_stage: { type: "enum", values: ["subscriber", "lead", "customer"] },
    annual_revenue: "currency",
    owner: "user",
  },
});

export default worker;
portal · contacts · ada@mariposalabs.ioCRM
ContactsAda Tan synced 14s ago
Email ada@mariposalabs.io Lifecycle customer Annual rev. $184,000 Owner Carter McKay Last sync airtable · row 47 Cursor c2VsZjpyZWNYNDcK…
Workers sync:airtableSync · Done. Synced 247 contacts in 412 ms. 14:22:08 UTC
CLOUDFLARE

Runs on your Cloudflare. Not ours.

Everything you build runs in a Cloudflare account you own — your code, your data, your customers’ tokens, on Workers, Durable Objects, Queues, KV, and D1. A deploy needs only your HubSpot and Cloudflare tokens. No HS-X account required. If HS-X disappeared tomorrow, every deployed app would keep running.

The deploy log is the whole setup: export two tokens and run hs-x deploy. No signup, no dashboard. Start without an account →

deploy log ~/portals/raleigh-rentals · main
$ export CLOUDFLARE_API_TOKEN=… HSX_HUBSPOT_PAK=… $ hs-x deploy [ok] Validating project 1 worker · 4 capabilities [ok] Generating artifacts .hs-x/manifest.json + refs * Unlinked deploy id deploy_raleigh-rentals_1784840164_ddda [ok] Cloudflare deploy hsx-local-08208c1f-rentals [ok] HubSpot build #1 app · action · card https://hsx-local-08208c1f-rentals.workers.dev $
capabilities deployed
UI contactPanelCard CRM contact UI dealTimelineTab CRM deal TOOL createQuote MCP · agents TOOL enrichContact MCP · agents SYNC airtableSync every 5 m SYNC postgresOpps every 10 m HOOK dealStageChanged webhook
TOOLKIT

CLI. SDK. MCP. API.

One toolchain for the developers on your team: a CLI, an SDK that’s just TypeScript, an MCP server so your coding agent can do everything you can, and a REST API for everything else. Same types, same project, same deploy.

HS-X CLI@hs-x/cli

A single command. One toolkit.

Scaffold, deploy, tail logs, manage portals. Token-efficient — coding agents can drive it without burning context.

$ npm i -g @hs-x/cli
$ hs-x init my-portal
$ hs-x deploy
Read the CLI docs
HS-X SDK@hs-x/sdk

TypeScript-first. Schema-driven.

Syncs, workflow actions, triggers, UI extensions — declared in plain TypeScript with a schema that types the rest of your code for you.

import { defineSource, defineWorker } from "@hs-x/sdk";

const airtable = defineSource({ … });

const worker = defineWorker("contacts");
worker.sync(airtable, { into: "contacts", … });

export default worker;
Read the SDK docs
HS-X MCPlocal dev

Your coding agent runs the dev loop.

An MCP server for your coding agent — validate the project, list capabilities, invoke any handler through the same dispatch path production uses.

$ claude mcp add hs-x -- \
    npx -y @hs-x/mcp
$ codex mcp add hs-x -- \
    npx -y @hs-x/mcp
// .cursor/mcp.json
{
  "mcpServers": {
    "hs-x": {
      "command": "npx",
      "args": ["-y", "@hs-x/mcp"]
    }
  }
}
// opencode.json
{
  "mcp": {
    "hs-x": {
      "type": "local",
      "command": ["npx", "-y", "@hs-x/mcp"]
    }
  }
}
Read the MCP spec
HS-X APIREST · v1

Plain HTTP, when that’s enough.

The same control plane the CLI and MCP speak — projects, deploys, revisions, rollbacks. Personal access tokens with deploy, read, and admin scopes, and an account audit log.

POST /v1/deploys/plan
GET  /v1/projects/{id}/revisions
POST /v1/projects/{id}/rollback
See the control-plane protocol
ARCHITECTURE

We maintain the toolkit. You own the runtime.

HS-X handles the hard plumbing — types, deploys, token storage, per-portal rate limits, audit logs. HubSpot owns the portal. You own the Cloudflare account it all runs on, and every deploy writes a plain wrangler.toml you can ship without us. No lock-in, by design.

/Not a developer?

We build HubSpot apps, too.

Don’t have a developer? The team behind HS-X builds on HS-X — marketplace apps, syncs, agent tools, and moving legacy custom cards to the new framework. By the project or on retainer.

Recent engagements
Mariposa Labsmarketplace app
TNZ Groupportal migration
Cohen Constructionworkflow actions
Raleigh Rentalsquote templates
Datadriven Co.hs-uix migration
Ready when you are

One install. The whole toolkit.

Scaffold an app, add a workflow action, and watch Breeze call it in a developer test account. All from hs-x init.