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 address
  • firstname - First name
  • lastname - Last name
  • company - Company name
  • phone - Phone number
  • lifecyclestage - 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 name
  • domain - Website domain
  • industry - Industry type
  • numberofemployees - Employee count
  • annualrevenue - 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 name
  • amount - Deal amount
  • dealstage - Current stage
  • closedate - Expected close date
  • pipeline - 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,
}

Resources

Related