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

# HubSpot

> Create, update, and look up HubSpot CRM contacts; fetch and search deals; look up companies and owners; log notes and tasks on a deal

## Overview

The HubSpot tools integrate with the HubSpot CRM API to manage contacts and read deals from your workflows. The contact tools key on the email address, so you can reconcile records without going through the Search API and its rate limit. The deal tools fetch a deal by ID or search deals by name, stage, owner, close or creation date, or any other property. The company and owner tools resolve the IDs a deal carries (its associated company, its `hubspot_owner_id`) into names, domains, and email addresses, and the note and task tools attach engagements to a deal without modifying the deal itself.

## Key Features

* `HUBSPOT_UPSERT_CONTACT`
  * Create a contact, or update the existing one with the same email address. Supports custom properties.
* `HUBSPOT_GET_CONTACT`
  * Fetch a contact by object ID or by email address. Returns `found: false` instead of failing when no contact matches.
* `HUBSPOT_GET_DEAL`
  * Fetch a deal by object ID, optionally with associated contact and company IDs. Returns `found: false` instead of failing when no deal matches.
* `HUBSPOT_SEARCH_DEALS`
  * Search deals by name, stage, pipeline, owner, or close / creation date range, with free-text and custom property filters. Paged.
* `HUBSPOT_GET_COMPANY`
  * Fetch a company by object ID, optionally with associated contact and deal IDs. Returns `found: false` instead of failing when no company matches.
* `HUBSPOT_GET_OWNER`
  * Fetch an owner by owner ID or by email address, returning their name, email, and user ID. Returns `found: false` instead of failing when no owner matches.
* `HUBSPOT_LIST_OWNERS`
  * List the owners in the account, optionally filtered by email or limited to archived owners. Paged.
* `HUBSPOT_CREATE_NOTE`
  * Create a note and attach it to a deal, contact, or company, with an optional timestamp and author.
* `HUBSPOT_CREATE_TASK`
  * Create a task with a due date, status, priority, and assignee, and attach it to a deal, contact, or company.

## Authentication

For setup instructions, [see the HubSpot credentials page](/en/pages/credentials/hubspot).

| Config field | Description |
| - | - |
| `access_token` | A HubSpot access token (select from workspace secrets). Needs `crm.objects.contacts.read` and `crm.objects.contacts.write` for the contact tools, `crm.objects.deals.read` for the deal tools, `crm.objects.companies.read` for `HUBSPOT_GET_COMPANY`, `crm.objects.owners.read` for the owner tools, and `crm.objects.contacts.write` for the note and task tools. |

### Example: Look Up a Contact, Then Create or Update It

```yaml theme={null}
- id: find_contact
  tool: HUBSPOT_GET_CONTACT
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: email
      value: "customer@example.com"
    - name: properties
      value: "email, firstname, lastname, company"
- id: upsert_contact
  tool: HUBSPOT_UPSERT_CONTACT
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: email
      value: "customer@example.com"
    - name: firstname
      value: "Ada"
    - name: lastname
      value: "Lovelace"
    - name: lifecyclestage
      value: "lead"
    - name: properties
      value: '{"hs_lead_status":"OPEN"}'
```

### Example: List Deals Closing This Month for One Owner

```yaml theme={null}
- id: search_deals
  tool: HUBSPOT_SEARCH_DEALS
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: owner_id
      value: "12345678"
    - name: close_date_from
      value: "2026-09-01T00:00:00+09:00"
    - name: close_date_to
      value: "2026-09-30T23:59:59+09:00"
    - name: sort_by
      value: "amount"
    - name: sort_direction
      value: "descending"
    - name: properties
      value: "dealname, amount, dealstage, closedate"
- id: get_deal
  tool: HUBSPOT_GET_DEAL
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: deal_id
      value: "{{steps.search_deals.result.deals[0].id}}"
    - name: associations
      value: "contacts, companies"
```

### Example: Resolve a New Deal's Owner and Company

```yaml theme={null}
- id: search_deals
  tool: HUBSPOT_SEARCH_DEALS
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: create_date_from
      value: "2026-09-30T09:00:00+09:00"
    - name: sort_by
      value: "createdate"
    - name: sort_direction
      value: "ascending"
- id: get_deal
  tool: HUBSPOT_GET_DEAL
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: deal_id
      value: "{{steps.search_deals.result.deals[0].id}}"
    - name: associations
      value: "contacts, companies"
- id: get_owner
  tool: HUBSPOT_GET_OWNER
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: owner_id
      value: "{{steps.get_deal.result.properties.hubspot_owner_id}}"
- id: get_company
  tool: HUBSPOT_GET_COMPANY
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: company_id
      value: "{{steps.get_deal.result.associations.companies.results[0].id}}"
    - name: properties
      value: "name, domain, industry, city"
```

### Example: Log a Meeting Summary and a Follow-up Task on a Deal

```yaml theme={null}
- id: create_note
  tool: HUBSPOT_CREATE_NOTE
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: deal_id
      value: "98765432"
    - name: body
      value: "<p><strong>Meeting 2026-10-01</strong></p><p>Reviewed pricing. Customer will confirm budget by next week.</p>"
- id: create_task
  tool: HUBSPOT_CREATE_TASK
  config:
    - name: access_token
      value: "{{secrets.HUBSPOT_ACCESS_TOKEN}}"
  input:
    - name: deal_id
      value: "98765432"
    - name: subject
      value: "Follow up on budget confirmation"
    - name: due_date
      value: "2026-10-08T09:00:00+09:00"
    - name: priority
      value: "HIGH"
    - name: owner_id
      value: "12345678"
```

## Inputs

### `HUBSPOT_UPSERT_CONTACT`

| Input | Required | Description |
| - | - | - |
| `email` | Yes | The lookup key. An existing contact with this email is updated, otherwise a new one is created. |
| `firstname`, `lastname`, `phone`, `company`, `jobtitle`, `website` | No | Standard contact properties. |
| `lifecyclestage` | No | e.g. `subscriber`, `lead`, `marketingqualifiedlead`, `customer`. |
| `properties` | No | Any other HubSpot properties as a JSON object of internal name → value, e.g. `{"hs_lead_status":"OPEN"}`. A `null` value clears the property. |

A named input left blank is skipped, not sent — HubSpot reads an empty string as "clear this property", so clearing has to be asked for explicitly through `properties` (`{"firstname": null}`). Named inputs win over the same key inside `properties`. Setting `properties.email` to something other than the `email` input is rejected. A difference in letter case alone is treated as the same address.

Returns `result.id`, `result.created`, `result.properties`, and the raw `result.contact`.

### `HUBSPOT_GET_CONTACT`

| Input | Required | Description |
| - | - | - |
| `contact_id` | One of the two | HubSpot contact object ID. |
| `email` | One of the two | Contact email address. |
| `properties` | No | Comma-separated property names, e.g. `email, firstname, company`. HubSpot returns only a minimal set when this is empty. Custom properties use their internal name, which you can find under **Settings → Properties**. |
| `associations` | No | Comma-separated object types to also fetch associated record IDs for, e.g. `companies, deals`. |

Returns `result.found`, `result.id`, `result.properties`, `result.associations`, and the raw `result.contact`.

### `HUBSPOT_GET_DEAL`

| Input | Required | Description |
| - | - | - |
| `deal_id` | Yes | HubSpot deal object ID (the number in the deal's URL, or an `id` from `HUBSPOT_SEARCH_DEALS`). |
| `properties` | No | Comma-separated property names, e.g. `dealname, amount, dealstage`. Defaults to `dealname, amount, dealstage, pipeline, closedate, hubspot_owner_id`. |
| `associations` | No | Comma-separated object types to also fetch associated record IDs for, e.g. `contacts, companies`. |

Returns `result.found`, `result.id`, `result.properties`, `result.associations`, and the raw `result.deal`.

### `HUBSPOT_SEARCH_DEALS`

All inputs are optional. Named filters are combined with AND.

| Input | Description |
| - | - |
| `query` | Free-text search, matched as a prefix against the deal name and other default searchable properties. |
| `deal_name` | Whole-word match on the deal name, e.g. `renewal` finds "Acme renewal 2026" but `renew` does not. Add `*` to match the start of a word (`renew*`). Use `query` for a quick keyword search instead. |
| `deal_stage` | Deal stage internal ID, e.g. `appointmentscheduled`, `closedwon`, or the numeric ID of a custom stage. |
| `pipeline` | Pipeline internal ID, e.g. `default`, or the numeric ID of a custom pipeline. |
| `owner_id` | HubSpot owner ID (`hubspot_owner_id`). Not the user ID shown under Settings → Users. |
| `close_date_from`, `close_date_to` | Close-date range, compared as `>=` / `<=` against the deal's `closedate` timestamp. ISO 8601 date or date-time; a date without a time is read as midnight UTC, so `close_date_to: "2026-09-30"` excludes deals closing later that day. To include the whole day, pass an explicit end time such as `2026-09-30T23:59:59+09:00`. |
| `create_date_from`, `create_date_to` | Creation-date range against the deal's `createdate`, with the same formats and end-of-day caveat as the close-date range. To pick up only deals created since a previous run, pass that run's timestamp as `create_date_from`. |
| `filters` | Additional filters as a JSON array of `{"propertyName","operator","value"}` objects, e.g. `[{"propertyName":"amount","operator":"GTE","value":"10000"}]`. Operators: `EQ`, `NEQ`, `LT`, `LTE`, `GT`, `GTE`, `BETWEEN` (`value` + `highValue`), `IN` / `NOT_IN` (`values` array), `HAS_PROPERTY`, `NOT_HAS_PROPERTY`, `CONTAINS_TOKEN`, `NOT_CONTAINS_TOKEN`. |
| `properties` | Comma-separated property names to return for each deal. Same default as `HUBSPOT_GET_DEAL`. |
| `sort_by` | Property to sort by, e.g. `createdate`, `closedate`, or `amount`. |
| `sort_direction` | `descending` (default) or `ascending`. Only used when `sort_by` is set. |
| `limit` | Deals per page, 1–200. Default 20. |
| `after` | Paging cursor from a previous result's `next_after`. |

Returns `result.deals` (each with `id` and `properties`), `result.count`, `result.total`, and `result.next_after` (`null` on the last page).

### `HUBSPOT_GET_COMPANY`

| Input | Required | Description |
| - | - | - |
| `company_id` | Yes | HubSpot company object ID (the number in the company's URL, or an ID from `HUBSPOT_GET_DEAL`'s `associations.companies`). |
| `properties` | No | Comma-separated property names, e.g. `name, domain, industry`. Defaults to `name, domain, industry, city, hubspot_owner_id`. |
| `associations` | No | Comma-separated object types to also fetch associated record IDs for, e.g. `contacts, deals`. |

Returns `result.found`, `result.id`, `result.properties`, `result.associations`, and the raw `result.company`.

### `HUBSPOT_GET_OWNER`

| Input | Required | Description |
| - | - | - |
| `owner_id` | One of the two | HubSpot owner ID — the `hubspot_owner_id` on a deal or contact. Not the user ID shown under Settings → Users. |
| `email` | One of the two | The owner's email address. |

Returns `result.found`, `result.id`, `result.email`, `result.first_name`, `result.last_name`, `result.user_id`, `result.archived`, and the raw `result.owner`.

### `HUBSPOT_LIST_OWNERS`

All inputs are optional.

| Input | Description |
| - | - |
| `email` | Only return the owner with this email address. |
| `archived` | `active` (default) or `archived`. HubSpot returns one set or the other, never both. |
| `limit` | Owners per page, 1–500. Default 100. |
| `after` | Paging cursor from a previous result's `next_after`. |

Returns `result.owners` (each with `id`, `email`, `first_name`, `last_name`, `user_id`, and `archived`), `result.count`, and `result.next_after` (`null` on the last page).

### `HUBSPOT_CREATE_NOTE`

| Input | Required | Description |
| - | - | - |
| `body` | Yes | The note text, as plain text or simple HTML. Up to 65,536 characters. |
| `deal_id`, `contact_id`, `company_id` | At least one | The record(s) to attach the note to. The note is associated with every record you pass. |
| `timestamp` | No | When the note was written, as ISO 8601 or epoch milliseconds. Defaults to now. |
| `owner_id` | No | HubSpot owner ID to record as the author. Left unset when empty (a service key or private app token has no user of its own). |
| `properties` | No | Any other engagement properties as a JSON object of internal name → value. Named inputs win over the same key inside `properties`. |

Returns `result.id`, `result.properties`, and the raw `result.note`.

### `HUBSPOT_CREATE_TASK`

| Input | Required | Description |
| - | - | - |
| `subject` | Yes | The task title. |
| `due_date` | Yes | When the task is due, as ISO 8601 or epoch milliseconds. HubSpot requires a due date on every task. |
| `deal_id`, `contact_id`, `company_id` | At least one | The record(s) to attach the task to. The task is associated with every record you pass. |
| `body` | No | Task description, as plain text or simple HTML. |
| `status` | No | `NOT_STARTED` (default), `IN_PROGRESS`, `WAITING`, `COMPLETED`, or `DEFERRED`. |
| `priority` | No | `LOW`, `MEDIUM`, or `HIGH`. Left unset unless you pass one. |
| `task_type` | No | `TODO` (default), `EMAIL`, or `CALL`. |
| `owner_id` | No | HubSpot owner ID to assign the task to. Left unset when empty, which leaves the task unassigned. |
| `properties` | No | Any other engagement properties as a JSON object of internal name → value. Named inputs win over the same key inside `properties`. |

Returns `result.id`, `result.properties`, and the raw `result.task`.

## Notes

* **Not found is not an error**: `HUBSPOT_GET_CONTACT`, `HUBSPOT_GET_DEAL`, `HUBSPOT_GET_COMPANY`, and `HUBSPOT_GET_OWNER` return `result.found = false` on a missing record, so "look up, and create it if missing" can be an ordinary condition step.
* **Notes and tasks do not edit the deal**: engagements are separate records associated with the deal, contact, or company you pass. None of the deal's own fields are written; HubSpot only refreshes its activity-derived properties (such as last activity date), which any workflow keyed on those will see. The Engagements API documents `crm.objects.contacts.write` for creating them, not `crm.objects.deals.write`.
* **Engagement timestamps**: `timestamp` and `due_date` accept ISO 8601 or epoch milliseconds. A date without a time is read as midnight UTC, so pass an explicit time with an offset (`2026-10-08T09:00:00+09:00`) when the hour matters.
* **Creates are not retried by the tool**: the HTTP call behind a note or task create is never repeated by the tool itself, whatever the failure, because a repeat could create the record twice. A step-level `retry` you configure still re-runs the step after a definitive rejection such as a 429, but the step opts out of it when the failure is ambiguous (the request timed out inside the tool, the connection dropped, or HubSpot answered 5xx). One gap remains: a step-level `timeout` that fires mid-request is raised by the runner, not the tool, so it is retried like any other error — keep `retry` off such steps, or set the step timeout well above the tool's own 30 seconds. Check HubSpot for the record before re-running the step.
* **Owner IDs vs user IDs**: `hubspot_owner_id` is not the user ID shown under Settings → Users. Use `HUBSPOT_GET_OWNER` to turn an owner ID into a name and email address, or `HUBSPOT_LIST_OWNERS` to find the owner ID for a given person.
* **Search limits**: HubSpot allows at most 6 filters per search (named fields and `filters` entries combined), returns at most 200 deals per page and 10,000 per query, and rate-limits the Search API separately at 5 requests per second per account. The search index can lag a few seconds behind writes, so a deal created moments earlier may not appear yet.
* **Date properties**: `closedate` and `createdate` are date-times in HubSpot. The range inputs are converted to epoch milliseconds for you; values in `filters` are sent as-is, so prefer epoch milliseconds there.
* **Incremental pickup**: `create_date_from` is inclusive (`>=`). If you pass the `createdate` of the newest deal from the previous run, that deal is returned again, so de-duplicate by `id` downstream.
* **Concurrent writes are last-write-wins**: HubSpot's CRM API has no optimistic locking, so overlapping updates resolve per property. Do not use `HUBSPOT_UPSERT_CONTACT` for read-modify-write accumulation (reading a score, adding to it, writing it back) across runs that may overlap — use a HubSpot calculated property instead.
* **Archived contacts**: a contact in HubSpot's recycle bin still reserves its email address, so an upsert against it cannot succeed. Restore it from the recycle bin, or use a different address.
* **Timeouts**: every request has a 30-second timeout, with automatic retries on rate limits and transient server errors (except note and task creates — see above).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.