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.

Why hubspot-cli Exists
Without hubspot-cli
- No official CRM CLI — the official
@hubspot/cliis 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
npm install -g hubspot-cli2. 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 gear → Integrations → Private Apps → Create 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 group | Scopes required |
|---|---|
| contacts | crm.objects.contacts.read + crm.objects.contacts.write |
| companies | crm.objects.companies.read + crm.objects.companies.write |
| deals | crm.objects.deals.read + crm.objects.deals.write |
| tickets | tickets |
| owners | crm.objects.owners.read |
| engagements (email read) | sales-email-read — only needed to read email body content; notes, calls, tasks, meetings work without it |
| lists | crm.lists.read + crm.lists.write |
| properties | crm.schemas.contacts.read + crm.schemas.contacts.writecrm.schemas.companies.read + crm.schemas.companies.writecrm.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
# 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 login4. Verify
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 JSONWhat hubspot-cli Gives Your Agent
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.
Pipeline & Owners
List pipelines, get stage details, pull deal stages, and look up owner assignments. Know exactly where every deal lives.
Engagements
Log notes, emails, calls, tasks, and meetings on any CRM record. Every customer touchpoint tracked, automatically.
Associations
Link contacts to companies, deals to contacts, any object to any object. HubSpot relationships managed programmatically.
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.
hubspot contacts search --query "john@acme.com"Check if contact already exists
hubspot companies search --query "Acme Corp"Check if company already exists
hubspot companies create --name "Acme Corp" --domain "acme.com"Create company if not found
hubspot contacts create --firstname "John" --lastname "Doe" --email "john@acme.com" --jobtitle "VP Sales"Create the contact
hubspot associations create --from-type contacts --from-id $CONTACT_ID --to-type companies --to-id $COMPANY_IDLink contact to company
hubspot engagements create-note --body "Met at SaaStr — inbound from LinkedIn. Warm intro via Mark." --contact-id $CONTACT_IDLog 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.
hubspot pipelines list --prettyGet pipeline IDs and stage names
hubspot deals list --stage "Proposal Sent" --prettyPull all deals in this stage
hubspot engagements list --object-type deals --object-id $DEAL_IDCheck 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.
hubspot deals search --query "acme"Find the Acme Corp deal
hubspot deals update $DEAL_ID --dealstage "closedwon" --closedate "2026-03-15"Move deal to Closed Won with close date
hubspot engagements create-note --body "Verbal commit received on 2026-03-10. Contract to follow." --deal-id $DEAL_IDLog 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.
hubspot companies search --query "acme"Find the Acme Corp company record
hubspot contacts list --company-id $COMPANY_ID --prettyGet all contacts at this company
hubspot deals list --company-id $COMPANY_ID --prettyGet all deals linked to company
hubspot engagements list --object-type companies --object-id $COMPANY_IDPull 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.
hubspot contacts get --email prospect@acme.comLook up the contact record
hubspot engagements create-meeting --subject "Discovery Call" --start 2026-03-10T14:00:00 --contact-id $CONTACT_IDLog meeting engagement on contact
hubspot engagements create-task --subject "Send follow-up summary" --due-date 2026-03-12 --contact-id $CONTACT_IDCreate 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.
hubspot search run --object-type contacts --filter '{"filters":[{"propertyName":"company_industry","operator":"EQ","value":"SAAS"}]}'Universal search with property filters
hubspot lists create --name "Q2 SaaS Outreach" --processing-type MANUALCreate the named list
hubspot lists add-members $LIST_ID --record-ids "..."Bulk-add all matching contact IDs
Commands Reference
hubspot contacts list [--top <n>] [--after <cursor>]List contacts with cursor paginationhubspot contacts get <id> | --email <email>Get a single contact by ID or emailhubspot contacts create --firstname <name> --lastname <name> --email <email> [--phone] [--company]Create a new contacthubspot contacts update <id> [--firstname] [--lastname] [--email] [--phone]Update contact propertieshubspot contacts delete <id>Delete a contacthubspot contacts search --query <text> [--properties <list>]Search contacts by any propertyhubspot contacts merge --primary-id <id> --secondary-id <id>Merge duplicate contactshubspot companies list [--top <n>] [--after <cursor>]List companies with paginationhubspot companies get <id>Get a single company recordhubspot companies create --name <name> [--domain] [--industry] [--city]Create a new companyhubspot companies update <id> [--name] [--domain] [--industry]Update company propertieshubspot companies delete <id>Delete a companyhubspot companies search --query <text>Search companies by name or domainhubspot deals list [--top <n>] [--stage <stage>] [--pipeline <id>]List deals, optionally filtered by stagehubspot deals get <id>Get a single deal recordhubspot deals create --dealname <name> --amount <num> --pipeline <id> --dealstage <stage>Create a new dealhubspot deals update <id> [--dealname] [--amount] [--dealstage] [--closedate]Update deal properties or move stagehubspot deals delete <id>Delete a dealhubspot deals search --query <text>Search deals by name or propertyhubspot tickets list [--top <n>] [--pipeline <id>] [--stage <stage>]List support ticketshubspot tickets get <id>Get a single tickethubspot tickets create --subject <text> --pipeline <id> --hs_pipeline_stage <stage>Create a new support tickethubspot tickets update <id> [--subject] [--hs_pipeline_stage] [--hs_ticket_priority]Update ticket properties or stagehubspot tickets delete <id>Delete a tickethubspot tickets search --query <text>Search tickets by subject or propertyhubspot owners list [--pretty]List all HubSpot owners (users)hubspot owners get <id> | --email <email>Get a single owner by ID or emailhubspot 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 metadatahubspot pipelines stages <pipeline-id> --object-type <type>List all stages in a pipelinehubspot engagements create-note --body <text> [--contact-id] [--deal-id] [--company-id]Log a note on any CRM recordhubspot engagements create-email --subject <text> --body <text> --to <email> [--contact-id]Log an outbound emailhubspot engagements create-call --body <text> --duration <ms> [--contact-id]Log a call with duration and noteshubspot engagements create-task --subject <text> --due-date <date> [--contact-id]Create a follow-up taskhubspot engagements create-meeting --subject <text> --start <iso> [--contact-id]Log a meeting engagementhubspot engagements list --object-type <type> --object-id <id>List all engagements on a recordhubspot engagements get <id>Get a single engagementhubspot engagements delete <id>Delete an engagementhubspot associations list --from-type <type> --from-id <id> --to-type <type>List all associations for a recordhubspot associations create --from-type <type> --from-id <id> --to-type <type> --to-id <id>Create an association between two objectshubspot associations delete --from-type <type> --from-id <id> --to-type <type> --to-id <id>Remove an associationhubspot lists list [--object-type <type>]List all contact or company listshubspot lists get <id>Get list metadata and member counthubspot lists create --name <name> --processing-type MANUAL|DYNAMICCreate a static or dynamic listhubspot lists update <id> [--name] [--processing-type]Update list metadatahubspot lists delete <id>Delete a listhubspot lists add-members <id> --record-ids <ids>Add contacts to a static listhubspot lists remove-members <id> --record-ids <ids>Remove contacts from a static listhubspot lists get-members <id> [--top <n>]Get all members of a listhubspot properties list --object-type <type>List all properties for an object typehubspot properties get <name> --object-type <type>Get a single property definitionhubspot properties create --object-type <type> --name <name> --label <label> --type <type> --field-type <type>Create a custom propertyhubspot properties update <name> --object-type <type> [--label] [--description]Update a property definitionhubspot properties delete <name> --object-type <type>Delete a custom propertyhubspot search run --object-type <type> --query <text> [--filter <json>] [--properties <list>] [--top <n>]Universal cross-object search with filter supporthubspot login [--access-token <token>]Authenticate and save token to config filehubspot logoutClear saved credentialshubspot status [--pretty]Show authentication state and portal infoMCP Server Setup
Every command is available as an MCP tool. Configure once and your agent has full HubSpot CRM access.
{
"mcpServers": {
"hubspot": {
"command": "npx",
"args": ["hubspot-cli", "mcp"],
"env": {
"HUBSPOT_ACCESS_TOKEN": "pat-na2-xxxxx"
}
}
}
}MCP tools registered (55 total):
OpenClaw Agent Setup
Give any OpenClaw agent full HubSpot CRM access. Install once, set the token, and the agent manages your CRM autonomously.
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.