> ## Documentation Index
> Fetch the complete documentation index at: https://docs.datazone.co/llms.txt
> Use this file to discover all available pages before exploring further.

# HubSpot

> Extract CRM objects from HubSpot using a private app access token.

# Overview

HubSpot is a CRM platform whose records — contacts, companies, deals, tickets, and custom objects — are exposed through its CRM API. Datazone connects with a **HubSpot private app access token** and extracts one CRM object type per extract via the CRM Search API.

## Prerequisites

Create a **private app** in your HubSpot account (**Settings → Integrations → Private Apps**), grant it read scopes for the object types you intend to extract, and copy its access token.

## Connection Parameters

Set on the source when you create it. Names match the API and CLI payload.

<ParamField path="name" type="string" required>
  **Name** — a unique identifier for your HubSpot source.
</ParamField>

<ParamField path="access_token" type="string" required>
  **Access Token** — the private app access token, for example `pat-eu1-…`. Stored encrypted.
</ParamField>

<ParamField path="base_url" type="string" default="https://api.hubapi.com">
  **Base URL** — HubSpot API base URL. Leave the default unless you have been given a region-specific host.
</ParamField>

## Extract Parameters

Set per extract, in `source_parameters`. See [Shared Extract Parameters](/reference/sources/overview#shared-extract-parameters) for `mode`, `replication_key`, and `schema_mapping`.

<ParamField path="table_name" type="string" required>
  **Object Type** — the singular CRM object type to extract: `contact`, `company`, `deal`, `ticket`, or the name of a custom object.
</ParamField>

<ParamField path="properties" type="string">
  Comma-separated list of properties to fetch, for example `email,firstname,lastname,hubspot_owner_id,lifecyclestage`.

  This **replaces** HubSpot's default property set rather than adding to it. Only `hs_object_id`, `createdate`, and `lastmodifieddate` are always returned — every other field, including custom properties and owner fields, must be listed explicitly. Omit the parameter to get HubSpot's default set. Discover available names with `GET /crm/v3/properties/{object}`.
</ParamField>

<ParamField path="page_size" type="integer" default="100">
  Records requested per API call. The Search API's maximum is 200.
</ParamField>

<ParamField path="batch_size" type="integer" default="100">
  Records written per batch on the Datazone side.
</ParamField>

<ParamField path="timeout" type="integer" default="60">
  Per-request timeout in seconds.
</ParamField>

<ParamField path="archived" type="boolean" default="false">
  Whether to fetch archived records. The Search API returns active records only, so this has no effect on the current extraction path.
</ParamField>

<ParamField path="api_version" type="string" default="2026-03">
  CRM API version segment. Retained for compatibility; it does not affect the Search endpoint used for extraction.
</ParamField>

## Output Shape

Each record is flattened one level, so the schema stays stable across records regardless of which properties are populated:

| Column       | Type    | Notes                                |
| ------------ | ------- | ------------------------------------ |
| `id`         | string  | Object id                            |
| `properties` | string  | JSON blob of the object's properties |
| `createdAt`  | string  | ISO 8601                             |
| `updatedAt`  | string  | ISO 8601                             |
| `archived`   | boolean |                                      |
| `url`        | string  | Record URL, when returned            |

Because `properties` arrives as a JSON string, unpack the fields you need in a downstream pipeline transform.

## Incremental Extraction

Records are read sorted by `hs_object_id` ascending, and each page is fetched with an `hs_object_id > last_id` filter. This sidesteps the Search API's 10,000-record offset cap, so collections of any size can be extracted. In `append` mode the last id seen becomes the resume cursor.

<Warning>
  Incremental extraction advances by object id, so it captures **newly created** records only — edits to records already extracted are not picked up. Schedule a periodic `overwrite` run to refresh updated records.
</Warning>

## Required Permissions

Grant the private app read scopes for each object type you extract, for example:

| Scope                        | Purpose                           |
| ---------------------------- | --------------------------------- |
| `crm.objects.contacts.read`  | Reading contacts                  |
| `crm.objects.companies.read` | Reading companies                 |
| `crm.objects.deals.read`     | Reading deals                     |
| `crm.schemas.custom.read`    | Reading custom object definitions |

## Limitations

* One CRM object type per extract
* `page_size` is capped at 200 by the Search API
* Rate limits (HTTP 429) and transient errors are retried automatically with backoff, which can extend the runtime of large extracts
* Nested property values are JSON-stringified rather than expanded into columns

## Next Steps

After configuring your HubSpot source:

1. Create extracts to specify which CRM object types to ingest
2. Configure scheduling for recurring extracts
3. Unpack the `properties` JSON in a pipeline transform
