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

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

$ npm i -g @hs-x/cli
or read the docs
works with via mcp 15-minute AI build
app.hubspot.com / contacts / 47821 / ada@mariposalabs.io synced 14s ago

Ada Tan

CEO · Mariposa Labs · ada@mariposalabs.io

Properties hs-uix · v2.3
MRR$4,820
DEALS12
OWNERCarter
SOURCEAirtable
Lifecyclecustomer
Annual rev.$184,000
IndustrySaaS
Last syncairtable · row 47
workers › sync:airtable

Done. Synced 247 contacts in 412 ms.

hs-uix › ContactPanel

Deployed in 1.2 s · 124 KiB.

tool › createQuote

Quote PDF sent · stage → Proposal.

hook › dealStageChanged

7 active hooks · 1.2k events / day.

Operations Data syncs Airtable · Contacts SYNC
Airtable contacts sync Active
Airtable
base · CRM
HubSpot
contacts
Synced247
Schedule5 m
Last run14 s
emailemail
stagelifecycle_stage
arrannual_revenue
Workflows Deal stage changed → Proposal ACTION

1.Send quote PDF

Cancel Save
Edit action Contacts in action

Generates a branded quote PDF from the deal record and emails it to the primary contact. Advances stage on send.

Template
PDF template*Deal token
deal-quote · saas
LocaleContact token
en-US
Email content
Subject*Deal token
Your Mariposa Labs proposal · deal.name
Body*
Hi contact.first_name,

Attached is the proposal we discussed. Let me know if you have any questions — happy to jump on a quick call.
Recipients
To*Contact token
deal.primary_contact.email
CcOwner
deal.owner.email
Reply-to
deals@hs-x.dev
Attachments
Include quote PDF
Attach signed MSA
Attach pricing one-pager
Conditions 2 rules · all must pass
if deal.amount > $5,000
and deal.owner = current_user
Recent runs last 7 days
today 14:22 Mariposa Labs · #4821 ✓ 1.2 s
today 11:08 Cedar & Bloom · #4807 ✓ 0.9 s
yest. 16:41 Halford Construction · #4793 ✓ 1.1 s
yest. 09:14 Topiary Studio · #4788 ! retry
Agents Breeze · customer agent MCP TOOL
Breeze
Hello! I'm Breeze, your HubSpot agent. How can I help you today?
Carter McKay
Send the Mariposa Labs quote — deal #4821, SaaS template.
Breeze
Quote PDF generated and emailed to ada@mariposalabs.io. Deal stage advanced to Proposal sent.
Carter McKay
Nice. What's the status on Cedar & Bloom?
Breeze
Cedar & Bloom (deal #4807) is in Negotiation. Last contact was 3 days ago. There's an open follow-up task assigned to you, due Friday.
Carter McKay
Any deals stalled this week?
Breeze
Three deals haven't moved in 7+ days:
· Halford Construction · $24,000 · Proposal sent
· Topiary Studio · $8,400 · Decision maker bought-in
· Glacier Coffee Co. · $12,200 · Discovery
Carter McKay
Draft a nudge email to Halford. Casual tone, mention the architectural drawings we sent last week.
Breeze
Drafted. Subject: "Quick follow-up on the Westwood drawings". Saved to your Halford Construction deal as a draft email. Want me to schedule it for Tuesday 9 a.m. ET?
Contacts Ada Tan CRM RECORD
Overview Activities Swag Intelligence
A

Ada Tan

CEO at Mariposa Labs

ada@mariposalabs.io
Send swag hs-uix/form · v2.3
Spend · this month $91 / $800
Order 2 items · ships from RDU
JBL JBL Go 3 speaker × 1 $55
KIT Welcome kit · branded × 2 $36
Shipping FormBuilder
Address 47 Hilton Ave · Brooklyn, NY 11205
Ship method
Standard Express · 2 d
Gift wrap
Note to Ada
Welcome to the team — looking forward to working together.
Send swag to Ada · $99
workers › sync:airtable

412 ms · 247 rows

workers › action:sendQuote

deployed

mcp › tool:createQuote

184 ms

hs-uix › swagPanel

1.2 s

portal · contacts · ada@mariposalabs.io CRM CARD
A

Ada Tan

CEO · Mariposa Labs · ada@mariposalabs.io

Send quote
Lifecyclecustomer Annual rev.$184,000 MRR$4,820 IndustrySaaS OwnerCarter McKay Sourceairtable · row 47 Last sync14 s ago
workflows · action WORKFLOW
/ Action — @hs-x

Send quote

Triggerstage → Proposal
Templatedeal-quote · saas
Save 1.2 s · 124 KiB
agent · breeze MCP TOOL
breeze · invoke
User Send the Mariposa Labs quote, SaaS template.
Tool createQuote(deal: "4821")
workers › sync:airtable

Synced 247 contacts in 412 ms.

hs-uix › ContactPanel

Deployed in 1.2 s · 124 KiB.

tool › createQuote

Quote PDF sent · stage → Proposal.

hook › dealStageChanged

7 active hooks · 1.2k events / day.

FIG. 03 — HS-X / PLATFORM Exploded view · 1:1
Drawing 03 / A Rev. 3.1 · May 2026
140 mm
01 hs-uix crm cards · panels · workflow actions · channels
02 @hs-x / sdk syncs · tools · hooks · mcp · sdk · cli
03 cloudflare · edge 330+ pop · durable objects · queues · r2
[a] · surfaces Schema-driven CRM cards First-party HubSpot UI primitives
[b] · workflow Action steps & quote PDFs Composable, typed, hot-reload
[c] · runtime Your Cloudflare, your data Edge Workers · 380 ms deploy
[d] · agents CLI · SDK · MCP Claude · Cursor · Breeze
DWGHS-X · 03A
SCALE1:1
DATE2026-05-14
REV3.1
Sources
HS-X · workers
Surfaces
Airtablecontacts · 247 rowsin
Stripewebhook · payment.okin
Postgresopportunities · viewin
GitHubissue.openedin
Cronevery 5 minutesin
hs-x · rack v0.2
sync 412 ms
hook 24 ms
tool 184 ms
ui ext idle
mcp live
queue 0 backlog
throughput 1.2k / day
Contact recordcrm card · hs-uixout
Deal stageworkflow actionout
Quote PDFtool · createQuoteout
Slack #dealsexternal apiout
Breeze agentmcp · invokeout
hs-x · portal 47821 · prod · cf-edge.dfw1 live
workers 12 + 0 / hr
syncs 3 412 ms p50
hooks · 24 h 1,248 + 12 %
mcp tools 47 3 portals
14:22:08 sync airtableSync upserted 247 contacts 412 ms
14:22:11 hook dealStageChanged · #4821 Proposal sent 24 ms
14:22:11 tool createQuote agent: breeze · deal 4821 184 ms
14:22:14 ui ContactPanel · deployed 124 KiB 1.2 s
14:22:20 sync postgresOpps 14 rows upserted 92 ms
14:22:24 hook stripe.payment.ok · invoice in_4D8 Slack #deals 38 ms
14:22:30 tool enrichContact · ada@mariposalabs.io properties: 6 221 ms
14:22:36 sync airtableSync diff 0 changes 38 ms
$ hs-x logs --project-id raleigh-rentals
SYNC

Sync any system into HubSpot — and keep it in sync.

Point a Worker at any API and its records land as Contacts, Companies, or any custom object, then stay current on a schedule. Cursors, identity 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.2
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 USD Owner Carter McKay Last sync airtable · row 47 Cursor c2VsZjpyZWNYNDcK…
Workers sync:airtableSync · Done. Synced 247 contacts in 412 ms. 14:22:08 UTC
UI EXTENSIONS

Build UI extensions that live inside HubSpot records.

hs-uix gives you React components that match HubSpot's look, typed from your portal's own schema. Every app card gets a backend in your Cloudflare — same types end to end, no glue code, and streaming responses for the slow work.

hs-uix · v2.3 · deployed
Surfaces6 live
Bundle124 KiB · gz
Last build1.2 s · clean
Portals3 · prod
portal · contacts · ada@mariposalabs.ioCRM CARD
ContactPanel · rendered FIG. 2A
[01] PROPERTIES KeyValueList
Lifecycle customer Annual rev. $184,000.00 Owner Carter McKay
[02] OPEN DEALS / 3 DataTable
Deal Amount Stage Q2 expansion $48,000 Proposal sent Seats add-on $12,400 Negotiation Support tier $6,000 Discovery
hs-uix v2.3 · 124 KiB · 1.2 s build · portal 47821
ContactPanel.tsx the ~30 lines behind this card hs-uix · app card
import { DataTable } from "hs-uix/datatable";
import { KeyValueList, SectionHeader } from "hs-uix/common-components";
import { formatCurrency } from "hs-uix/utils";
import { Tile, hubspot } from "@hubspot/ui-extensions";

function ContactPanel({ context, runServerless }) {
  return (
    <Tile>
      <SectionHeader title="Properties" />
      <KeyValueList
        items={[
          { label: "Lifecycle", value: "Customer" },
          { label: "Annual revenue", value: formatCurrency(184000) },
          { label: "Owner", value: "Carter McKay" },
        ]}
      />
      <SectionHeader title="Open deals" />
      <DataTable
        columns={[
          { id: "name", label: "Deal", sortable: true },
          { id: "amount", label: "Amount", format: "currency" },
          { id: "stage", label: "Stage", filter: "enum" },
        ]}
        fetch={() => runServerless({ name: "listDeals", parameters: { contactId: context.crm.objectId } })}
      />
    </Tile>
  );
}

hubspot.extend(() => <ContactPanel />);
hs-uix ui:ContactPanel + action:sendQuote · Deployed in 1.2 s · 124 KiB 14:21:47 UTC
AGENT TOOLS

Write it once. Ship an agent tool and a custom workflow action.

One TypeScript function becomes an agent tool Breeze can call and a custom workflow action your team can drop into any workflow — same code, same auth. Coding agents can exercise it locally through the HS-X MCP server's invoke tool while you build.

createQuote · workflow action
SurfacesWorkflow · Breeze
Calls · 24 h2,184
p50 latency184 ms
Authportal-scoped token
createQuote.tsWORKFLOW ACTION
worker.tool("createQuote", {
  label: "Create quote",
  description: "Generate a quote PDF and email it to the primary contact.",
  objectType: "deal",
  input: {
    template: { type: "enum", values: ["standard", "saas"] },
  },
  agent: {
    description: "Create and send a quote for this deal.",
    expose: ["template"],
  },
  async handler({ input, enrolledObject, hubspot }) {
    const pdf = await renderQuote(enrolledObject, input.template);

    await hubspot.crm.objects.emails.basicApi.create({ /* … */ });

    return { message: `Quote sent for deal ${enrolledObject.id}.` };
  },
});
agent · breezeCHAT
User
Can you send the Mariposa Labs quote? It's deal #4821, SaaS template.
Breeze
Thinking · matched intent to createQuote
Tool createQuote(dealId: "4821", template: "saas")
Breeze
Quote PDF generated and emailed to ada@mariposalabs.io. The deal stage moved to Proposal sent.
Workers workflowAction:createQuote · Done after 184 ms. 14:22:42 UTC
WEBHOOKS

Run code when anything happens in HubSpot.

Set up a webhook subscription for deal-stage changes, form submissions, any HubSpot event — and run a handler on your runtime. We verify every signature, drop duplicate deliveries, and queue the flood when HubSpot pushes faster than you can handle. You write the handler.

CLOUDFLARE

Runs on your Cloudflare. Not ours.

Your code, data, and customers' tokens live in a Cloudflare account you own — Workers, Durable Objects, Queues, KV, D1, all of it. 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.

That's the whole setup, exactly as shown: export two tokens and run hs-x deploy. No signup, no dashboard — the Unlinked deploy id in the log is the proof. 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. A CLI for you. An SDK that's just TypeScript. An MCP server so your coding agent can do everything you can. A REST API for everything else. Same types, same project, same deploy.

HS-X CLI@hs-x/cli

A single command. One platform.

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. PATs 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 own the platform. You own the runtime.

hs-x handles the hard platform 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 builder?

We ship HubSpot work, too.

Need it built? The team behind hs-x ships HubSpot work on hs-x — marketplace apps, syncs, agent tools, card migrations. Retainer or by the project.

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, wire a workflow action to an agent tool, watch Breeze call it against a developer test account. All from hs-x init.