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

# HubSpot

> Configure HubSpot connections in Genesis for CRM reads, record updates, and optional approval-gated duplicate merges.

## Overview

HubSpot appears in **Config -> Connections** under **Dev Tools**. Genesis supports one saved auth mode:

* `api_key` — a HubSpot **Service Key** or **Private App** bearer token.

After setup, Genesis tests the connection against `api.hubapi.com` and reads the portal identity from HubSpot account details. On Snowflake Native App / SPCS deployments, HubSpot connections declare egress for `api.hubapi.com`.

## Setup workflow

<Steps>
  <Step title="Open the HubSpot connector">
    Go to **Config -> Connections**, choose **Dev Tools**, then select **HubSpot**.
  </Step>

  <Step title="Create a Service Key or Private App token">
    In HubSpot, open **Settings -> Integrations** and create a **Service Key** (preferred) or **Private App** token. HubSpot has deprecated private apps in favor of Service Keys for single-account API access; either works in Genesis as a static bearer token.
  </Step>

  <Step title="Grant required scopes">
    The token must include every scope Genesis needs. During the post-save **Test Connection** step, Genesis lists the required scopes and provides **Copy required scopes** so you can paste them into HubSpot's scope picker.

    Required scopes:

    * `crm.objects.companies.read`
    * `crm.objects.companies.write`
    * `crm.objects.contacts.read`
    * `crm.objects.contacts.write`
    * `crm.objects.deals.read`
    * `crm.objects.tickets.read`
    * `crm.schemas.companies.read`
    * `crm.schemas.contacts.read`
    * `crm.schemas.custom.read`
    * `account-info.security.read`

    The `account-info.security.read` scope is required because connection testing and merge tenant binding read the portal identity from `/account-info/v3/details`. The `deals` and `tickets` read scopes are required because both are readable object types; without them those reads fail with `MISSING_SCOPES`.
  </Step>

  <Step title="Enter connection fields">
    Paste the token into **Service Key or Private App Token**. Optionally enable approval-gated merge settings (see below). Save the connection.
  </Step>

  <Step title="Test, egress, and save">
    On SPCS deployments, complete egress preflight in the post-save guide. Save the connection and run **Test Connection**. If scopes are missing, HubSpot returns a `403` with `MISSING_SCOPES` — add the scopes Genesis lists, update the token in HubSpot, and retry.
  </Step>
</Steps>

<Note>
  If your deployment uses outbound allowlists or external access controls, allow Genesis to reach `api.hubapi.com`.
</Note>

## Connection fields

### `api_key`

| **Field** | **Type** | **Required** | **Default** | **Notes** |
| - | - | - | - | - |
| **`api_key`** | String (secret) | Yes | none | Service Key or Private App bearer token with the required scopes above. |
| **`merge_enabled`** | Select (`false` / `true`) | No | `false` | Opt in to approval-gated merges. Defaults to off. |
| **`merge_survivorship_policy`** | Text (JSON) | Yes when merge is enabled | none | Merge review fields for previews and approvals. Required when `merge_enabled` is `true`. |

## Approval-gated merge

Merges are opt-in per connection and irreversible. Enable **Enable Approval-Gated Merge** (`merge_enabled`) only when operators are ready to govern duplicate consolidation.

When merge is enabled, set **Merge Review Fields (JSON)** on the connection. The policy must include:

* `version` — non-empty string bound into the approval digest.
* `preview_fields` — non-empty list of HubSpot property names shown on the human review surface.

HubSpot determines final field values during a merge, so do not set survivorship `rules`. Every review field is stored in the approval digest.

Example:

```json theme={null}
{
  "version": "v1",
  "preview_fields": ["email", "firstname", "lastname"]
}
```

Genesis supports merging **contacts** and **companies** only, with one survivor and exactly one loser per merge. HubSpot's merge endpoint accepts a single `objectIdToMerge`; HubSpot determines the resulting record id and redirects both input ids to it.

### Merge workflow

1. **Preview** — `hubspot_connector` with `PREVIEW_MERGE`, or `POST /api/crm/hubspot/merge/preview`. Writes nothing; returns projection and digest.
2. **Request approval** — `REQUEST_MERGE_APPROVAL` or `POST /api/crm/hubspot/merge/approvals` with optional `expected_digest` from the preview.
3. **Human approve** — `POST /api/crm/hubspot/merge/approvals/{approval_id}/approve`. Only a genuinely authenticated human can approve; agents cannot substitute. There is no approval screen yet — approval is made through this authenticated API route.
4. **Execute** — `EXECUTE_APPROVED_MERGE` or `POST /api/crm/hubspot/merge/approvals/{approval_id}/execute` with the bound connection name.

Approval lifetime defaults to `3600` seconds and is capped by `hubspot.max_approval_ttl_seconds` in App Config (default `86400`).

Connection-specific API behavior is listed in the provider-neutral [CRM merge endpoints](/docs/Genesis-API/API-Reference#crm-merge-endpoints).

## What it enables

After setup, Genesis can use `hubspot_connector_tools` for bounded CRM reads and writes on **contacts** and **companies**, with read-only access to **deals** and **tickets**. Administrators can extend readable and writable object types through the `hubspot.extra_objects` App Config setting. With merge enabled, agents and operators can run the preview → approval → execute merge path for duplicate contacts and companies.

## Related pages

* [Connections](/docs/Setup/Connections)
* [HubSpot Connector Tools](/docs/Genbot-Toolkit/HubSpot-Connector-Tools)
* [CRM merge endpoints](/docs/Genesis-API/API-Reference#crm-merge-endpoints)
