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

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

$ curl -fsSL hs-x.dev | sh
or read the docs
app.hubspot.com / contacts / 47821 / ada@mariposalabs.io synced 14s ago

Ada Tan

CEO · Mariposa Labs · ada@mariposalabs.io

Properties hs-uix · v2.4
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.4
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 parity 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 v3.1
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
$ npx hs-x tail --portal 47821
[ 01 ] 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 · v3.1
import { defineSource, defineWorker, env } from "@hs-x/sdk";

const airtableContacts = defineSource({
  name: "airtableContacts",
  auth: { type: "bearer", token: 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,
        },
      })),
    };
  },
});

export default defineWorker(({ worker }) => {
  worker.sync(airtableContacts, {
    into: "contacts",
    schedule: "5m",
    schema: {
      email: "email",
      lifecycle_stage: { type: "enum", values: ["subscriber", "lead", "customer"] },
      annual_revenue: "currency",
      owner: "user",
    },
  });
});
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
[ 02 ] 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.4 · deployed
Surfaces6 live
Bundle124 KiB · gz
Last build1.2 s · clean
Portals3 · prod
ContactPanel.tsxhs-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 />);
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.4 · 124 KiB · 1.2 s build · portal 47821
hs-uix ui:ContactPanel + action:sendQuote · Deployed in 1.2 s · 124 KiB 14:21:47 UTC
[ 03 ] 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. It's exposed over MCP too, so coding agents like Claude and Cursor can call it just the same.

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.",
  input: {
    dealId: "deal",
    template: { type: "enum", values: ["standard", "saas"] },
  },
  expose: ["workflow", "breeze"],
  async run({ input, ctx }) {
    const deal = await ctx.hubspot.deals.get(input.dealId);
    const contact = await deal.primaryContact();
    const pdf = await renderQuote(deal, input.template);

    await ctx.hubspot.files.upload(`Quote-${deal.id}.pdf`, pdf);
    await ctx.hubspot.emails.send({
      to: contact.email,
      subject: `Quote ${deal.id}`,
      template: "deal-quote",
      attach: [`Quote-${deal.id}.pdf`],
    });

    return { message: `Quote sent to ${contact.email}.` };
  },
});
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
[ 04 ] 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.

[ 05 ] 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.

deploy log ~/portals/raleigh-rentals · main
$ npx hs-x deploy hs-x 3.1.0 Bundled 4 extensions 124 KiB · 0.8 s Validated schema 0 errors · 2 warnings Deployed to portal portal 47821 · 2.1 s Worker pushed cf-edge · 380 ms https://app.hubspot.com/portal/47821/extensions $
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
[ 07 ] 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 we hand you the infrastructure-as-code file as your way out. 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 platform.

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.