HubSpot¶
Sync CRM data from HubSpot into your data warehouse.
| Feature | Details |
|---|---|
| Auth | API Key (Private App Token) |
| Env Variable | HUBSPOT_API_KEY |
| Incremental | Yes |
| Default Resources | contacts, companies, deals, tickets, products, quotes, owners, properties, pipelines_deals, pipelines_tickets |
| dlt Package | hubspot |
Managing this source in the Web UI
After setup, manage this source from the Sources page in the Web UI (http://localhost:8800/sources). Trigger syncs, view history, and monitor status without using the CLI. See Web UI — Sources.
Prerequisites¶
- A HubSpot account (app.hubspot.com)
- A Private App Token (not a legacy API key)
Create a Private App Token¶
- In HubSpot, go to Settings (gear icon) > Integrations > Private Apps
- Click Create a private app
- Name it (e.g., "Dango Data Pipeline")
- Under Scopes, grant these read permissions:
crm.objects.contacts.readcrm.objects.companies.readcrm.objects.deals.readcrm.objects.quotes.readtickets(if syncing tickets)
- Click Create app
- Copy the access token
Legacy API keys are deprecated
HubSpot deprecated legacy API keys in November 2022. Use Private App Tokens instead. Private App Tokens start with pat- and have granular scope control.
Setup¶
Via Wizard (Recommended)¶
? Select a data source: HubSpot
? Source name: hubspot
? Environment variable for API key [HUBSPOT_API_KEY]: HUBSPOT_API_KEY
? Select resources:
[x] contacts
[x] companies
[x] deals
[x] tickets
[x] products
[x] quotes
[x] owners
[x] properties
[x] pipelines_deals
[x] pipelines_tickets
Via Configuration File¶
Edit .dango/sources.yml:
version: '1.0'
sources:
- name: hubspot
type: hubspot
enabled: true
description: HubSpot CRM data
hubspot:
api_key_env: HUBSPOT_API_KEY
resources:
- contacts
- companies
- deals
- tickets
- products
- quotes
- owners
- properties
- pipelines_deals
- pipelines_tickets
First Sync¶
Configuration¶
Available Resources¶
| Resource | Description | Default |
|---|---|---|
contacts | Contact records | Yes |
companies | Company records | Yes |
deals | Deal/opportunity records | Yes |
tickets | Support tickets | Yes |
products | Product catalog | Yes |
quotes | Sales quotes | Yes |
owners | HubSpot users/owners | Yes |
properties | Custom property definitions | Yes |
pipelines_deals | Deal pipeline stages | Yes |
pipelines_tickets | Ticket pipeline stages | Yes |
All 10 resources are synced by default. To sync a subset, specify only the resources you want:
Tables Loaded¶
Data loads into the raw_{source_name} schema:
| Resource | Table Name |
|---|---|
| contacts | raw_hubspot.contacts |
| companies | raw_hubspot.companies |
| deals | raw_hubspot.deals |
| tickets | raw_hubspot.tickets |
| products | raw_hubspot.products |
| quotes | raw_hubspot.quotes |
| owners | raw_hubspot.owners |
Query example:
SELECT id, properties__firstname, properties__lastname, properties__email
FROM raw_hubspot.contacts
LIMIT 10;
HubSpot properties
HubSpot stores custom fields as nested properties. In DuckDB, these appear as properties__field_name columns.
Sync Behavior¶
- Incremental: After the first full sync, subsequent syncs fetch only records modified since the last sync.
- Write disposition:
mergefor most resources (upsert by ID). Thepropertiesresource usesreplace(full reload each sync). - First sync: Loads all historical data. Large accounts (100k+ contacts) may take 15-30 minutes.
Common Issues¶
"401 Unauthorized"¶
- Verify the token in
.envis correct and not expired - Check that the Private App is still active in HubSpot settings
- Ensure the token has the required scopes for the resources you selected
Missing Data / Partial Results¶
- Some resources require specific scopes. Check your Private App's scope settings in HubSpot.
- Archived or deleted records are not included by default.
Rate Limiting¶
HubSpot enforces API rate limits (100 calls per 10 seconds for Private Apps). Dango handles rate limiting automatically with retry logic. Very large accounts may see slower sync times.
"403 Forbidden" on Specific Resources¶
Your Private App token lacks the required scope. Go to Settings > Integrations > Private Apps, edit your app, and add the missing scope.
Next Steps¶
- Adding Sources - Full wizard walkthrough
- Sync Modes - Incremental vs. full refresh
- Source Catalog - All available data sources
- Transformations - Transform HubSpot data with dbt
- HubSpot Private Apps Documentation