HubSpot Adapter
The HubSpot adapter provides access to CRM data including contacts, companies, and deals with OAuth2 authentication.
Installation
npm install @openetl/hubspot
Features
- OAuth2 Authentication - Secure authentication with automatic token refresh
- CRM Objects - Access contacts, companies, deals, and more
- Cursor Pagination - Efficient pagination for large datasets
- Property Selection - Retrieve only the fields you need
- Full CRUD Support - Download and upload operations
Authentication
The HubSpot adapter uses oauth2 authentication:
const vault = {
'hubspot-auth': {
id: 'hubspot-auth',
type: 'oauth2',
credentials: {
client_id: process.env.HUBSPOT_CLIENT_ID,
client_secret: process.env.HUBSPOT_CLIENT_SECRET,
access_token: process.env.HUBSPOT_ACCESS_TOKEN,
refresh_token: process.env.HUBSPOT_REFRESH_TOKEN,
},
},
};
Quick Start
import { Orchestrator } from 'openetl';
import { hubspot } from '@openetl/hubspot';
const vault = {
'hubspot-auth': {
id: 'hubspot-auth',
type: 'oauth2',
credentials: {
client_id: process.env.HUBSPOT_CLIENT_ID,
client_secret: process.env.HUBSPOT_CLIENT_SECRET,
access_token: process.env.HUBSPOT_ACCESS_TOKEN,
refresh_token: process.env.HUBSPOT_REFRESH_TOKEN,
},
},
};
const etl = Orchestrator(vault, { hubspot });
const pipeline = {
id: 'export-contacts',
source: {
id: 'contacts-source',
adapter_id: 'hubspot',
endpoint_id: 'contacts',
credential_id: 'hubspot-auth',
fields: ['email', 'firstname', 'lastname', 'company', 'phone'],
pagination: { type: 'cursor', itemsPerPage: 100 },
},
};
const result = await etl.runPipeline(pipeline);
console.log(`Exported ${result.data.length} contacts`);
Endpoints
contacts
Retrieve or create CRM contacts.
const connector = {
adapter_id: 'hubspot',
endpoint_id: 'contacts',
credential_id: 'hubspot-auth',
fields: ['email', 'firstname', 'lastname', 'company', 'phone', 'lifecyclestage'],
pagination: { type: 'cursor', itemsPerPage: 100 },
};
Common contact properties:
email- Email addressfirstname- First namelastname- Last namecompany- Company namephone- Phone numberlifecyclestage- Lifecycle stage (subscriber, lead, customer, etc.)hs_lead_status- Lead status
companies
Retrieve or create CRM companies.
const connector = {
adapter_id: 'hubspot',
endpoint_id: 'companies',
credential_id: 'hubspot-auth',
fields: ['name', 'domain', 'industry', 'numberofemployees', 'annualrevenue'],
pagination: { type: 'cursor', itemsPerPage: 100 },
};
Common company properties:
name- Company namedomain- Website domainindustry- Industry typenumberofemployees- Employee countannualrevenue- Annual revenue
deals
Retrieve or create CRM deals.
const connector = {
adapter_id: 'hubspot',
endpoint_id: 'deals',
credential_id: 'hubspot-auth',
fields: ['dealname', 'amount', 'dealstage', 'closedate', 'pipeline'],
pagination: { type: 'cursor', itemsPerPage: 100 },
};
Common deal properties:
dealname- Deal nameamount- Deal amountdealstage- Current stageclosedate- Expected close datepipeline- Sales pipeline
Pagination
HubSpot uses cursor-based pagination for efficient data retrieval:
pagination: {
type: 'cursor',
itemsPerPage: 100, // Max 100 per request
}
The adapter automatically handles cursor tokens and fetches all pages.
Filtering
Filter contacts by property values:
filters: [
{ field: 'lifecyclestage', operator: '=', value: 'customer' },
{ field: 'hs_lead_status', operator: '=', value: 'QUALIFIED' },
]
Complete Example
import { Orchestrator, Pipeline } from 'openetl';
import { hubspot } from '@openetl/hubspot';
import { postgresql } from '@openetl/postgresql';
const vault = {
'hubspot-auth': {
id: 'hubspot-auth',
type: 'oauth2',
credentials: {
client_id: process.env.HUBSPOT_CLIENT_ID,
client_secret: process.env.HUBSPOT_CLIENT_SECRET,
access_token: process.env.HUBSPOT_ACCESS_TOKEN,
refresh_token: process.env.HUBSPOT_REFRESH_TOKEN,
},
},
'warehouse': {
id: 'warehouse',
type: 'basic',
credentials: {
host: 'localhost',
database: 'analytics',
username: 'etl',
password: process.env.DB_PASSWORD,
},
},
};
const etl = Orchestrator(vault, { hubspot, postgresql });
const pipeline: Pipeline = {
id: 'sync-contacts',
source: {
id: 'contacts-source',
adapter_id: 'hubspot',
endpoint_id: 'contacts',
credential_id: 'hubspot-auth',
fields: ['email', 'firstname', 'lastname', 'company', 'lifecyclestage'],
filters: [
{ field: 'lifecyclestage', operator: '=', value: 'customer' },
],
pagination: { type: 'cursor', itemsPerPage: 100 },
},
target: {
id: 'contacts-target',
adapter_id: 'postgresql',
endpoint_id: 'table_insert',
credential_id: 'warehouse',
config: { schema: 'crm', table: 'hubspot_contacts' },
fields: ['email', 'first_name', 'last_name', 'company', 'lifecycle_stage'],
},
error_handling: {
max_retries: 3,
retry_interval: 2000,
fail_on_error: true,
},
};
const result = await etl.runPipeline(pipeline);
console.log(`Synced ${result.data.length} contacts`);
Rate Limiting
HubSpot has API rate limits. The adapter handles rate limit responses (HTTP 429) with automatic retry and exponential backoff.
error_handling: {
max_retries: 5,
retry_interval: 1000,
fail_on_error: true,
}