Open Source·AI Agent Infrastructure

Your CRM, Controlled by Agents.

Contacts. Companies. Deals. Tickets. 55 commands. Every one doubles as an MCP tool.

HubSpot’s official CLI only covers CMS. There’s no official CRM CLI.
So we built hubspot-cli — the missing CLI for agents on HubSpot.

Install from npm
55
Commands
11
API Groups
CLI
+ MCP Native
OpenClaw
OpenClaw
CLI / MCP
HubSpot CRM
contacts · companies · deals · tickets · engagements

Why hubspot-cli Exists

Without hubspot-cli

  • No official CRM CLI — the official @hubspot/cli is CMS-only (themes, modules, serverless)
  • Agents can’t programmatically manage contacts or deals without building custom API wrappers
  • Manual API auth per request — no token resolution strategy
  • No MCP support — agents can’t call HubSpot as a native tool
  • JSON output requires custom parsing logic for every endpoint

With hubspot-cli

  • 55 commands covering the full CRM API surface
  • Single Private App token, 3-tier resolution: flag → env var → config file
  • Every command is also an MCP tool — plug into any AI agent
  • JSON-first output — pipe to jq, save to files, feed to agents
  • 1-minute setup, MIT licensed, Private App scopes only

Quick Start

1. Install

Terminal
npm install -g hubspot-cli

2. Create a Private App access token

Private Apps are HubSpot’s recommended method for simple API access — fully supported, not going away.

1. In HubSpot, click the Settings gearIntegrationsPrivate AppsCreate a private app

2. Basic info tab: Give it a name (e.g. hubspot-cli-agent) and optional description

3. Scopes tab: Add the scopes for the command groups you want to use:

Command groupScopes required
contactscrm.objects.contacts.read + crm.objects.contacts.write
companiescrm.objects.companies.read + crm.objects.companies.write
dealscrm.objects.deals.read + crm.objects.deals.write
ticketstickets
ownerscrm.objects.owners.read
engagements
(email read)
sales-email-read — only needed to read email body content; notes, calls, tasks, meetings work without it
listscrm.lists.read + crm.lists.write
properties
crm.schemas.contacts.read + crm.schemas.contacts.write
crm.schemas.companies.read + crm.schemas.companies.write
crm.schemas.deals.read + crm.schemas.deals.write

4. Click Create app → go to the Auth tab → click Show token → copy it (starts with pat-na followed by your region)

3. Authenticate

Terminal
# Option A: environment variable (recommended for agents)
export HUBSPOT_ACCESS_TOKEN=pat-na2-xxxxx

# Option B: interactive login (saves to ~/.hubspot-cli/config.json)
hubspot login

4. Verify

Terminal
hubspot status --pretty
# {"authenticated":true,"portal":"Your Portal Name","hub_id":12345678}

hubspot contacts list --top 5 --pretty
# Returns your first 5 contacts as formatted JSON

What hubspot-cli Gives Your Agent

32 cmds

CRM Objects

Full CRUD + search for contacts, companies, deals, and tickets. List, get, create, update, delete, search — the full surface across all four core objects.

5 cmds

Pipeline & Owners

List pipelines, get stage details, pull deal stages, and look up owner assignments. Know exactly where every deal lives.

8 cmds

Engagements

Log notes, emails, calls, tasks, and meetings on any CRM record. Every customer touchpoint tracked, automatically.

3 cmds

Associations

Link contacts to companies, deals to contacts, any object to any object. HubSpot relationships managed programmatically.

8 cmds

Lists & Segments

Create static and dynamic lists, manage members, power segments. Build and maintain your prospecting lists without touching the HubSpot UI.

MCP Server

Every command is exposed as an MCP tool. Universal cross-object search included. Claude, Cursor, OpenClaw, and any MCP client can call all 55 commands.

Agent Workflows

Real prompts agents use to manage HubSpot CRM end-to-end.

New Lead → Full CRM Setup

Agent Prompt

I just got a new lead — John Doe, VP Sales at Acme Corp, john@acme.com. Create the contact, create the company if it doesn't exist, link them, and add a note about how we met.

Agent searches for existing records, creates what's missing, links the contact to the company, and logs the first engagement — full CRM setup in one autonomous flow.

1
hubspot contacts search --query "john@acme.com"

Check if contact already exists

2
hubspot companies search --query "Acme Corp"

Check if company already exists

3
hubspot companies create --name "Acme Corp" --domain "acme.com"

Create company if not found

4
hubspot contacts create --firstname "John" --lastname "Doe" --email "john@acme.com" --jobtitle "VP Sales"

Create the contact

5
hubspot associations create --from-type contacts --from-id $CONTACT_ID --to-type companies --to-id $COMPANY_ID

Link contact to company

6
hubspot engagements create-note --body "Met at SaaStr — inbound from LinkedIn. Warm intro via Mark." --contact-id $CONTACT_ID

Log first engagement note

Morning Pipeline Review

Agent Prompt

Review my open deals. Show me anything in 'Proposal Sent' stage that hasn't had activity in 7+ days.

Agent pulls the pipeline, filters by stage, then checks engagement history on each deal — surfacing stale opportunities before they go cold.

1
hubspot pipelines list --pretty

Get pipeline IDs and stage names

2
hubspot deals list --stage "Proposal Sent" --pretty

Pull all deals in this stage

3
hubspot engagements list --object-type deals --object-id $DEAL_ID

Check last activity on each deal

Move Deal Forward

Agent Prompt

The Acme Corp deal just verbally agreed. Move it to Closed Won, update the close date, and log a note about the verbal commitment.

Agent finds the deal, updates the stage and close date in one command, then logs the verbal commitment as an engagement — pipeline hygiene automated.

1
hubspot deals search --query "acme"

Find the Acme Corp deal

2
hubspot deals update $DEAL_ID --dealstage "closedwon" --closedate "2026-03-15"

Move deal to Closed Won with close date

3
hubspot engagements create-note --body "Verbal commit received on 2026-03-10. Contract to follow." --deal-id $DEAL_ID

Log the verbal commitment

Research an Account

Agent Prompt

Pull everything we know about Acme Corp — their contacts, open deals, recent activity, and any notes from the last 30 days.

Agent pulls the company record, enumerates all associated contacts and deals, then surfaces engagement history — a complete account brief, generated autonomously.

1
hubspot companies search --query "acme"

Find the Acme Corp company record

2
hubspot contacts list --company-id $COMPANY_ID --pretty

Get all contacts at this company

3
hubspot deals list --company-id $COMPANY_ID --pretty

Get all deals linked to company

4
hubspot engagements list --object-type companies --object-id $COMPANY_ID

Pull all recent engagement activity

Schedule a Discovery Call

Agent Prompt

Book a discovery call with prospect@acme.com for next Tuesday 2pm EST. Log it as a meeting engagement on their contact record.

Agent looks up the contact, creates a meeting engagement with full metadata, then adds a follow-up task — booking and pipeline tracking in one shot.

1
hubspot contacts get --email prospect@acme.com

Look up the contact record

2
hubspot engagements create-meeting --subject "Discovery Call" --start 2026-03-10T14:00:00 --contact-id $CONTACT_ID

Log meeting engagement on contact

3
hubspot engagements create-task --subject "Send follow-up summary" --due-date 2026-03-12 --contact-id $CONTACT_ID

Create follow-up task

Build a Prospecting List

Agent Prompt

Create a list of all contacts at companies in the 'SaaS' industry with more than 50 employees. Add them to our Q2 outreach list.

Agent runs a cross-object search with property filters, creates a named list, and bulk-adds all matching records — a prospecting segment built in minutes, not hours.

1
hubspot search run --object-type contacts --filter '{"filters":[{"propertyName":"company_industry","operator":"EQ","value":"SAAS"}]}'

Universal search with property filters

2
hubspot lists create --name "Q2 SaaS Outreach" --processing-type MANUAL

Create the named list

3
hubspot lists add-members $LIST_ID --record-ids "..."

Bulk-add all matching contact IDs

Commands Reference

contacts (7 commands)
hubspot contacts list [--top <n>] [--after <cursor>]List contacts with cursor pagination
hubspot contacts get <id> | --email <email>Get a single contact by ID or email
hubspot contacts create --firstname <name> --lastname <name> --email <email> [--phone] [--company]Create a new contact
hubspot contacts update <id> [--firstname] [--lastname] [--email] [--phone]Update contact properties
hubspot contacts delete <id>Delete a contact
hubspot contacts search --query <text> [--properties <list>]Search contacts by any property
hubspot contacts merge --primary-id <id> --secondary-id <id>Merge duplicate contacts
companies (6 commands)
hubspot companies list [--top <n>] [--after <cursor>]List companies with pagination
hubspot companies get <id>Get a single company record
hubspot companies create --name <name> [--domain] [--industry] [--city]Create a new company
hubspot companies update <id> [--name] [--domain] [--industry]Update company properties
hubspot companies delete <id>Delete a company
hubspot companies search --query <text>Search companies by name or domain
deals (6 commands)
hubspot deals list [--top <n>] [--stage <stage>] [--pipeline <id>]List deals, optionally filtered by stage
hubspot deals get <id>Get a single deal record
hubspot deals create --dealname <name> --amount <num> --pipeline <id> --dealstage <stage>Create a new deal
hubspot deals update <id> [--dealname] [--amount] [--dealstage] [--closedate]Update deal properties or move stage
hubspot deals delete <id>Delete a deal
hubspot deals search --query <text>Search deals by name or property
tickets (6 commands)
hubspot tickets list [--top <n>] [--pipeline <id>] [--stage <stage>]List support tickets
hubspot tickets get <id>Get a single ticket
hubspot tickets create --subject <text> --pipeline <id> --hs_pipeline_stage <stage>Create a new support ticket
hubspot tickets update <id> [--subject] [--hs_pipeline_stage] [--hs_ticket_priority]Update ticket properties or stage
hubspot tickets delete <id>Delete a ticket
hubspot tickets search --query <text>Search tickets by subject or property
owners (2 commands)
hubspot owners list [--pretty]List all HubSpot owners (users)
hubspot owners get <id> | --email <email>Get a single owner by ID or email
pipelines (3 commands)
hubspot pipelines list --object-type <type>List all pipelines for an object type (deals, tickets)
hubspot pipelines get <id> --object-type <type>Get a single pipeline with metadata
hubspot pipelines stages <pipeline-id> --object-type <type>List all stages in a pipeline
engagements (8 commands)
hubspot engagements create-note --body <text> [--contact-id] [--deal-id] [--company-id]Log a note on any CRM record
hubspot engagements create-email --subject <text> --body <text> --to <email> [--contact-id]Log an outbound email
hubspot engagements create-call --body <text> --duration <ms> [--contact-id]Log a call with duration and notes
hubspot engagements create-task --subject <text> --due-date <date> [--contact-id]Create a follow-up task
hubspot engagements create-meeting --subject <text> --start <iso> [--contact-id]Log a meeting engagement
hubspot engagements list --object-type <type> --object-id <id>List all engagements on a record
hubspot engagements get <id>Get a single engagement
hubspot engagements delete <id>Delete an engagement
associations (3 commands)
hubspot associations list --from-type <type> --from-id <id> --to-type <type>List all associations for a record
hubspot associations create --from-type <type> --from-id <id> --to-type <type> --to-id <id>Create an association between two objects
hubspot associations delete --from-type <type> --from-id <id> --to-type <type> --to-id <id>Remove an association
lists (8 commands)
hubspot lists list [--object-type <type>]List all contact or company lists
hubspot lists get <id>Get list metadata and member count
hubspot lists create --name <name> --processing-type MANUAL|DYNAMICCreate a static or dynamic list
hubspot lists update <id> [--name] [--processing-type]Update list metadata
hubspot lists delete <id>Delete a list
hubspot lists add-members <id> --record-ids <ids>Add contacts to a static list
hubspot lists remove-members <id> --record-ids <ids>Remove contacts from a static list
hubspot lists get-members <id> [--top <n>]Get all members of a list
properties (5 commands)
hubspot properties list --object-type <type>List all properties for an object type
hubspot properties get <name> --object-type <type>Get a single property definition
hubspot properties create --object-type <type> --name <name> --label <label> --type <type> --field-type <type>Create a custom property
hubspot properties update <name> --object-type <type> [--label] [--description]Update a property definition
hubspot properties delete <name> --object-type <type>Delete a custom property
search (1 command)
hubspot search run --object-type <type> --query <text> [--filter <json>] [--properties <list>] [--top <n>]Universal cross-object search with filter support
auth (3 commands)
hubspot login [--access-token <token>]Authenticate and save token to config file
hubspot logoutClear saved credentials
hubspot status [--pretty]Show authentication state and portal info

MCP Server Setup

Every command is available as an MCP tool. Configure once and your agent has full HubSpot CRM access.

Claude Desktop / Cursor (~/.cursor/mcp.json or claude_desktop_config.json)
{
  "mcpServers": {
    "hubspot": {
      "command": "npx",
      "args": ["hubspot-cli", "mcp"],
      "env": {
        "HUBSPOT_ACCESS_TOKEN": "pat-na2-xxxxx"
      }
    }
  }
}

MCP tools registered (55 total):

contacts_listcontacts_getcontacts_createcontacts_updatecontacts_deletecontacts_searchcontacts_mergecompanies_listcompanies_getcompanies_createcompanies_updatecompanies_deletecompanies_searchdeals_listdeals_getdeals_createdeals_updatedeals_deletedeals_searchtickets_listtickets_gettickets_createtickets_updatetickets_deletetickets_searchowners_listowners_getpipelines_listpipelines_getpipelines_stagesengagements_create_noteengagements_create_emailengagements_create_callengagements_create_taskengagements_create_meetingengagements_listengagements_getengagements_deleteassociations_listassociations_createassociations_deletelists_listlists_getlists_createlists_updatelists_deletelists_add_memberslists_remove_memberslists_get_membersproperties_listproperties_getproperties_createproperties_updateproperties_deletesearch_run

OpenClaw Agent Setup

Give any OpenClaw agent full HubSpot CRM access. Install once, set the token, and the agent manages your CRM autonomously.

1
Install on the agent's server
npm install -g hubspot-cli
2
Set access token in agent environment
export HUBSPOT_ACCESS_TOKEN=pat-na2-xxxxx — or use hubspot login to save to config
3
Start MCP server
hubspot mcp — runs on stdio transport, compatible with any MCP client
4
Add CRM instructions to SOUL.md
Tell the agent how to create contacts, log engagements, and move deals through your pipeline stages
5
Test from Slack
"Find all open deals over $10k" — agent calls hubspot search via MCP, returns structured JSON

Architecture

Every API endpoint is a CommandDefinition — one source of truth powering both the CLI subcommand and the MCP tool. The CRM Object Factory generates CRUD+search for all four core objects from a single template.

src/
├── core/
│   ├── types.ts      # CommandDefinition, HubSpotClient interfaces
│   ├── client.ts     # REST client (cursor pagination, 429 backoff)
│   ├── auth.ts       # 3-tier token resolution
│   ├── config.ts     # ~/.hubspot-cli/config.json
│   ├── errors.ts     # Typed error classes
│   └── output.ts     # JSON output + --fields filtering
├── commands/
│   ├── contacts/     # 7 commands
│   ├── companies/    # 6 commands
│   ├── deals/        # 6 commands
│   ├── tickets/      # 6 commands
│   ├── owners/       # 2 commands
│   ├── pipelines/    # 3 commands
│   ├── engagements/  # 8 commands
│   ├── associations/ # 3 commands
│   ├── lists/        # 8 commands
│   ├── properties/   # 5 commands
│   └── search/       # 1 command
├── crm-factory.ts    # CRM Object Factory (createCrmObjectCommands)
└── mcp/
    └── server.ts     # MCP server (auto-registers all commands as tools)

Same pattern as instantly-cli + clay-gtm-cli + ms365-cli

The CommandDefinition architecture is shared across all TOFU CLIs. One schema definition generates the Commander.js subcommand, the Zod schema, and the MCP tool — zero duplication.

CRM Object Factory

createCrmObjectCommands() generates list, get, create, update, delete, and search for contacts, companies, deals, and tickets from a single factory. New CRM objects require one config object.

Ready to give your agent a full HubSpot CRM brain?

Install hubspot-cli, set your access token in 60 seconds, and your agent can create contacts, move deals, log engagements, and manage your entire CRM.

Need agents wired into your HubSpot CRM? We deploy and manage the full setup.