@maxnate/provider-hubspot
v0.1.1
Published
HubSpot CRM provider for @maxnate/crm-core. Implements CrmProviderAdapter against HubSpot v3 CRM API with private-app bearer auth and HMAC-SHA256 webhook verification.
Maintainers
Readme
@maxnate/provider-hubspot
HubSpot CRM provider for @maxnate/crm-core.
Implements CrmProviderAdapter with contact upsert + search via the HubSpot CRM v3 API.
npm install @maxnate/provider-hubspot @maxnate/crm-coreCredentials
| Field | Description |
|---|---|
| accessToken | HubSpot Private App access token (pat-...). Settings > Integrations > Private Apps. |
OAuth flow tokens (
oauth-...) are accepted in the same field but the adapter does not auto-refresh them. Use a Private App for unattended workloads.
Property Mapping
HubSpot property names are lowercase and snake_case (firstname, lastname, mobilephone). The provider accepts a propertyMap in CrmProviderConfig to translate canonical Contact fields to HubSpot property names:
propertyMap: {
firstName: 'firstname',
lastName: 'lastname',
phone: 'mobilephone'
}Custom properties pass through attributes unchanged.
Usage
import { createCrmProviderRegistry } from '@maxnate/crm-core'
import { HubSpotCrmProvider } from '@maxnate/provider-hubspot'
const registry = createCrmProviderRegistry({ configStore, secretsCodec })
registry.register(new HubSpotCrmProvider())
await registry.configureProvider('tenant-1', {
id: 'hubspot', name: 'HubSpot', enabled: true,
credentials: { accessToken: process.env.HUBSPOT_PRIVATE_APP_TOKEN! },
propertyMap: { firstName: 'firstname', lastName: 'lastname' }
})
// Upsert (idempotent on email)
const result = await registry.upsertContact('tenant-1', 'hubspot', {
email: '[email protected]',
firstName: 'Jane',
lastName: 'Doe',
attributes: { lead_source: 'web', campaign: '2026-q2' }
})
// → { contactId: '12345', created: true }
// Search
const contacts = await registry.findContacts('tenant-1', 'hubspot', {
email: '[email protected]',
limit: 10
})Idempotency
Contact upsert is idempotent on email — HubSpot is the source of truth for the vid / contactId. The adapter does not maintain its own idempotency cache for upserts; the provided CrmIdempotencyStore is used only for retried jobs.
Webhooks
HubSpot supports outbound webhooks signed with HMAC-SHA256 over the request body. The current adapter version does not ship a built-in webhook handler — wire your own route and use the HubSpot signature verification documented at https://developers.hubspot.com/docs/api/webhooks/validating-requests. A future release of @maxnate/crm-core will add a unified webhook surface.
Requirements
- Node.js >= 18
@maxnate/crm-core^0.1.0- HubSpot Private App with
crm.objects.contacts.readandcrm.objects.contacts.writescopes
License
MIT
