HubSpot CRM Integration
Connection
- Base URL:
https://api.hubapi.com
- Auth:
Authorization: Bearer $HUBSPOT_PRIVATE_APP_TOKEN or legacy
HUBSPOT_ACCESS_TOKEN
- Env vars:
HUBSPOT_PRIVATE_APP_TOKEN preferred,
HUBSPOT_ACCESS_TOKEN legacy
- Caching: 10-minute in-memory cache, max 120 entries
Server Lib
- File:
server/lib/hubspot.ts
Exported Functions
| Function |
Description |
getDealPipelines() |
All deal pipelines with stages |
getVisiblePipelines(pipelines) |
Filter to visible pipelines |
getMetricsPipelines(pipelines) |
Filter to metrics-relevant pipelines |
getDealProperties() |
HubSpot deal property metadata |
getAllDeals(extraProperties?) |
All deals (paginated, up to ~10k) |
getDealOwners() |
HubSpot owner id → owner name map |
computeSalesMetrics(deals, pipelines, filter?) |
Compute won/lost/pipeline metrics |
Script Usage
# Search deals for a named account/deal
pnpm action hubspot-deals --query="Example Corp" --limit=10 --properties=dealname,amount,dealstage
# Structured cohort: products field = Publish, closed-won New Business deals
pnpm action hubspot-deals --product=Publish --pipeline="New Business" --closedStatus=won --closedDateFrom=2025-06-01 --closedDateTo=2026-06-01
# List deals
pnpm action hubspot-deals --properties=dealname,amount,dealstage
# Find custom fields before requesting them
pnpm action hubspot-deal-properties --search=nbm
Key Patterns & Gotchas
getAllDeals paginates using limit=100 and HubSpot after token (up to 100 pages)
hubspot-deals --query="Customer" uses HubSpot search and should be the first path for named account/deal deep dives. Avoid pulling every deal first.
- For deal cohorts, use structured
hubspot-deals filters (product, pipeline, closedStatus, closedDateFrom, closedDateTo) and report the returned filters/count in the methodology.
- Do not use
query for property-specific filters. query="Publish" is broad full-text search across deals and can include records where products is not Publish.
- If
hubspot-deals cannot express the needed CRM endpoint/filter/body/pagination, use provider-api-catalog --provider=hubspot, optionally provider-api-docs, then provider-api-request --provider=hubspot with the exact HubSpot API request.
hubspot-deals returns normalized stage_name, pipeline_name, owner_name, is_closed_won, and is_deal_closed fields under deal.properties
- For AE QBR or NBM deck work, HubSpot is the source of truth. Request
nbm_meeting_booked_date, nbm_meeting_complete_date, and hs_manual_forecast_category through hubspot-deals; do not use warehouse SQL as the first path unless HubSpot is unavailable and the user approves the fallback
- Optional deal properties are filtered against HubSpot property metadata before fetching, so deployments without a custom field do not fail the whole action
- The default deal fetch includes the hard-coded
hs_v2_date_entered stage property names with embedded stage IDs when they exist in the connected portal
computeSalesMetrics infers won/lost stages from probability metadata or label text; identifies POV stages by names containing "proof of value", "pov", "poc"
- When looking up a customer, search deals by name, then get associated company via
/crm/v3/objects/deals/{id}/associations/companies, then contacts via /crm/v3/objects/companies/{id}/associations/contacts
HubSpot Company Properties (BigQuery staging table)
Table: your-project-id.dbt_staging.hubspot_companies
company_name, company_id, company_domain_name
upcoming_renewal_date, customer_stage, hs_csm_sentiment
company_owner_name, root_org_id
customer_segmentation, current_enterprise_arr, company_status
Cross-Reference
- HubSpot company → contacts →
dim_hs_contacts.builder_user_id → BigQuery usage data
- HubSpot deal → company → Pylon support tickets, Gong sales calls
1---2name: hubspot-23description: Query HubSpot CRM for deals, contacts, companies, and sales metrics. Use this skill when the user asks about sales pipeline, deal status, or customer CRM data.4---56# HubSpot CRM Integration78## Connection910- **Base URL**: `https://api.hubapi.com`11- **Auth**: `Authorization: Bearer $HUBSPOT_PRIVATE_APP_TOKEN` or legacy12 `HUBSPOT_ACCESS_TOKEN`13- **Env vars**: `HUBSPOT_PRIVATE_APP_TOKEN` preferred,14 `HUBSPOT_ACCESS_TOKEN` legacy15- **Caching**: 10-minute in-memory cache, max 120 entries1617## Server Lib1819- **File**: `server/lib/hubspot.ts`2021### Exported Functions2223| Function | Description |24| ------------------------------------------------ | ------------------------------------ |25| `getDealPipelines()` | All deal pipelines with stages |26| `getVisiblePipelines(pipelines)` | Filter to visible pipelines |27| `getMetricsPipelines(pipelines)` | Filter to metrics-relevant pipelines |28| `getDealProperties()` | HubSpot deal property metadata |29| `getAllDeals(extraProperties?)` | All deals (paginated, up to ~10k) |30| `getDealOwners()` | HubSpot owner id → owner name map |31| `computeSalesMetrics(deals, pipelines, filter?)` | Compute won/lost/pipeline metrics |3233## Script Usage3435```bash36# Search deals for a named account/deal37pnpm action hubspot-deals --query="Example Corp" --limit=10 --properties=dealname,amount,dealstage3839# Structured cohort: products field = Publish, closed-won New Business deals40pnpm action hubspot-deals --product=Publish --pipeline="New Business" --closedStatus=won --closedDateFrom=2025-06-01 --closedDateTo=2026-06-014142# List deals43pnpm action hubspot-deals --properties=dealname,amount,dealstage4445# Find custom fields before requesting them46pnpm action hubspot-deal-properties --search=nbm47```4849## Key Patterns & Gotchas5051- `getAllDeals` paginates using `limit=100` and HubSpot `after` token (up to 100 pages)52- `hubspot-deals --query="Customer"` uses HubSpot search and should be the first path for named account/deal deep dives. Avoid pulling every deal first.53- For deal cohorts, use structured `hubspot-deals` filters (`product`, `pipeline`, `closedStatus`, `closedDateFrom`, `closedDateTo`) and report the returned filters/count in the methodology.54- Do not use `query` for property-specific filters. `query="Publish"` is broad full-text search across deals and can include records where `products` is not Publish.55- If `hubspot-deals` cannot express the needed CRM endpoint/filter/body/pagination, use `provider-api-catalog --provider=hubspot`, optionally `provider-api-docs`, then `provider-api-request --provider=hubspot` with the exact HubSpot API request.56- `hubspot-deals` returns normalized `stage_name`, `pipeline_name`, `owner_name`, `is_closed_won`, and `is_deal_closed` fields under `deal.properties`57- For AE QBR or NBM deck work, HubSpot is the source of truth. Request `nbm_meeting_booked_date`, `nbm_meeting_complete_date`, and `hs_manual_forecast_category` through `hubspot-deals`; do not use warehouse SQL as the first path unless HubSpot is unavailable and the user approves the fallback58- Optional deal properties are filtered against HubSpot property metadata before fetching, so deployments without a custom field do not fail the whole action59- The default deal fetch includes the hard-coded `hs_v2_date_entered` stage property names with embedded stage IDs when they exist in the connected portal60- `computeSalesMetrics` infers won/lost stages from probability metadata or label text; identifies POV stages by names containing "proof of value", "pov", "poc"61- When looking up a customer, search deals by name, then get associated company via `/crm/v3/objects/deals/{id}/associations/companies`, then contacts via `/crm/v3/objects/companies/{id}/associations/contacts`6263## HubSpot Company Properties (BigQuery staging table)6465Table: `your-project-id.dbt_staging.hubspot_companies`6667- `company_name`, `company_id`, `company_domain_name`68- `upcoming_renewal_date`, `customer_stage`, `hs_csm_sentiment`69- `company_owner_name`, `root_org_id`70- `customer_segmentation`, `current_enterprise_arr`, `company_status`7172## Cross-Reference7374- HubSpot company → contacts → `dim_hs_contacts.builder_user_id` → BigQuery usage data75- HubSpot deal → company → Pylon support tickets, Gong sales calls