Skip to main content

HubSpot integration

Create, update, search, and watch HubSpot CRM contacts, companies, deals, and tickets on behalf of your clients.

What it does

The HubSpot integration connects a client CRM once and lets you read and write the four core object types: contacts, companies, deals, and tickets. You can create, update, fetch, search, and delete records, manage associations between them, add notes, add contacts to a static list, look up owners, and start workflows the moment a record changes in HubSpot.

Every record action takes an objectType parameter that is templated into the request, so the same Create Record or Update Record action works with HubSpot custom objects when you type the object type, not only the four built-in types. There is no dropdown that lists or introspects custom-object properties, so you supply the object type and property names yourself.

HubSpot triggers and actions are in beta

Every HubSpot trigger and action currently ships with a beta badge. Trigger nodes are hidden in the editor unless beta nodes are turned on for your workspace. Expect the behavior described here to be stable, but treat the integration as evolving.

Connect a HubSpot account

HubSpot connects through OAuth 2.0. There is no API key, subdomain, or secret to paste. The person who authorizes the connection must be a HubSpot super admin, because HubSpot only lets super admins approve a connected app.

  1. Open Connections in your workspace

    Open the workspace in TaskJuice and go to Connections.

  2. Choose HubSpot and start the connect flow

    Select HubSpot and start the OAuth connect flow.

  3. Sign in to HubSpot as a super admin

    Sign in to the HubSpot account you want to authorize, using your own account or your client's, and pick the HubSpot account to connect.

  4. Approve the requested CRM permissions

    Approve the CRM read, write, and schema permissions HubSpot lists. TaskJuice requests the scopes in the table below.

  5. Return to your workspace

    TaskJuice returns you to the workspace with the connection ready to use in any workflow.

For the full connect flow that applies to every OAuth app, see Connect an account.

Scopes requested

TaskJuice requests these 11 scopes during authorization. All are requested by default.

ScopeGrants
crm.objects.contacts.readRead contacts
crm.objects.contacts.writeCreate and update contacts
crm.objects.companies.readRead companies
crm.objects.companies.writeCreate and update companies
crm.objects.deals.readRead deals
crm.objects.deals.writeCreate and update deals
crm.objects.tickets.readRead tickets
crm.objects.tickets.writeCreate and update tickets
crm.schemas.contacts.readRead the contact property schema
crm.schemas.companies.readRead the company property schema
crm.schemas.deals.readRead the deal property schema

To disconnect, remove the connection in TaskJuice, which deletes the stored credentials. A HubSpot super admin can also remove the connected app from HubSpot's connected-apps settings.

Triggers

HubSpot delivers all 10 triggers as real-time webhooks, so a run starts as soon as the event happens rather than on a poll interval. Each trigger fires once per business event: one contact created starts one run.

HubSpot webhook payloads are minimal. They carry the record ID and, for property changes, the changed property name and value, but not the full record. To act on the rest of a record's fields, pair the trigger with a Get Record action that fetches the full object by ID.

TriggerSlugFires when
Contact Createdhubspot/contact-createdA new contact is created. Payload carries the contact ID; use Get Record to fetch full data.
Contact Updatedhubspot/contact-updatedA contact property changes.
Contact Deletedhubspot/contact-deletedA contact is deleted.
Company Createdhubspot/company-createdA new company is created. Payload carries the company ID; use Get Record to fetch full data.
Company Updatedhubspot/company-updatedA company property changes.
Deal Createdhubspot/deal-createdA new deal is created. Payload carries the deal ID; use Get Record to fetch full data.
Deal Updatedhubspot/deal-updatedA deal property changes, except stage changes, which fire Deal Stage Changed instead.
Deal Stage Changedhubspot/deal-stage-changedA deal's pipeline stage changes.
Ticket Createdhubspot/ticket-createdA new ticket is created. Payload carries the ticket ID; use Get Record to fetch full data.
Ticket Updatedhubspot/ticket-updatedA ticket property changes.

A deal moving between pipeline stages fires hubspot/deal-stage-changed, not hubspot/deal-updated. Choose the trigger that matches whether you care about stage moves specifically or any property change.

Trigger output

All 10 triggers share the same output shape.

FieldTypeRequiredDefaultDescription
objectIdnumberYesNoneHubSpot record ID
eventIdnumberYesNoneUnique event ID for idempotency
portalIdnumberYesNoneHubSpot portal/account ID
subscriptionTypestringYesNoneEvent type
occurredAtnumberYesNoneUnix timestamp in milliseconds
changeSourcestringNoNoneWhat caused the change
attemptNumbernumberNoNoneDelivery attempt number
propertyNamestringNoNoneChanged property name; present only on updated and stage-changed triggers
propertyValuestringNoNoneChanged property value; present only on updated and stage-changed triggers

The propertyName and propertyValue fields appear only on the updated and stage-changed triggers. Created and deleted triggers do not carry them. On hubspot/deal-stage-changed, propertyName is always dealstage and propertyValue is the new pipeline stage value.

Actions

There are 12 actions, all driven by HTTP configuration, and all require the HubSpot connection. The six record actions take an objectType config field. Its dropdown lists contacts, companies, deals, and tickets; typing a custom object type also works because the value is templated into the request URL.

ActionSlugWhat it does
Create Recordhubspot/create-recordCreates a contact, company, deal, or ticket.
Update Recordhubspot/update-recordUpdates an existing record by ID.
Get Recordhubspot/get-recordRetrieves a single record by ID.
Delete Recordhubspot/delete-recordDeletes a record by ID.
Search Recordshubspot/search-recordsSearches records with filters, sorting, and property selection.
List Recordshubspot/list-recordsLists records of one object type.
Upsert Contacthubspot/upsert-contactCreates or updates contacts in batch by a unique identifier property.
Create Associationhubspot/create-associationAssociates two CRM records.
Remove Associationhubspot/remove-associationRemoves an association between two records.
Create Notehubspot/create-noteCreates a note engagement and optionally associates it with records.
Add Contact to Listhubspot/add-contact-to-listAdds contacts to a static list.
Get Ownerhubspot/get-ownerRetrieves a HubSpot owner by ID.

Record action inputs

ActionConfigRequired inputsOptional inputs
Create RecordobjectType (enum)properties (object)associations (array)
Update RecordobjectType (enum)recordId (string), properties (object)None
Get RecordobjectType (enum)recordId (string)properties (comma-separated string of property names to return)
Delete RecordobjectType (enum)recordId (string)None
Search RecordsobjectType (enum)filterGroups (array of filter-group objects with AND/OR logic)sorts (array), properties (array), limit (number, default 10, max 100), after (cursor)
List RecordsobjectType (enum)Nonelimit (number, default 10, max 100), after (cursor), properties (comma-separated string)

Get Record takes its properties input as a comma-separated string of property names. Search Records and List Records take properties as an array. Match the shape to the action you are using.

Other action inputs

ActionRequired inputsOptional inputs
Upsert Contactinputs (array, each item { "properties": {...}, "idProperty": "email" })None
Create AssociationfromObjectType, fromObjectId, toObjectType, toObjectId, associationSpec (array, e.g. [{"associationCategory":"HUBSPOT_DEFINED","associationTypeId":1}])None
Remove AssociationfromObjectType, fromObjectId, toObjectType, toObjectIdNone
Create Noteproperties (object, e.g. {"hs_note_body":"...","hs_timestamp":"..."})associations (array)
Add Contact to ListlistId (string), contactIds (array of contact ID numbers)None
Get OwnerownerId (string)None

A few behaviors worth knowing when you wire these up:

  • Search Records returns { total, results[], paging } and paginates with the after cursor. List Records returns { results[], paging } with no total.
  • Upsert Contact is contacts-only in this version and returns status, results[], numErrors, and errors[]. For other object types, use Create Record or Update Record.
  • Create Note stores the note text in hs_note_body.

Dynamic pickers

Two fields populate from the connected HubSpot account instead of being typed by hand:

  • A deal pipeline picker, useful when you set a deal's pipeline or stage.
  • An owner picker, useful when you assign a record to an owner.

These are the only two dynamic pickers. There is no record picker for contacts, companies, deals, or tickets, so you supply record IDs from earlier steps or from a Search Records action.

Errors

Actions map HubSpot's HTTP responses to TaskJuice error codes. Each action times out after 15 seconds and retries up to 2 times on retryable errors with exponential backoff. Non-retryable errors stop the step.

Error codeHTTPRetryableWhat it means and what to do
VALIDATION_ERROR400NoHubSpot rejected the request. Check property names and required fields.
AUTH_EXPIRED401NoThe connection is no longer valid. Reauthorize the HubSpot connection, then resume affected runs.
MISSING_SCOPES403NoThe connection lacks a required permission. Reconnect as a super admin to grant it.
OBJECT_NOT_FOUND404NoThe record, list, or owner ID does not exist.
OBJECT_ALREADY_EXISTS409NoA conflicting record already exists. Returned by Create Record only.
RATE_LIMITED429YesHubSpot throttled the request. TaskJuice retries with backoff.
PROVIDER_ERROR500, 502, 503YesHubSpot had a server error. TaskJuice retries.

HubSpot access tokens are short-lived, and TaskJuice refreshes them for you, so you should not normally see an auth error. If a token cannot be refreshed (for example, the connected app was removed in HubSpot), the next action returns AUTH_EXPIRED and the connection needs reauthorization.

Known limitations

  • Webhook payloads are minimal. Triggers deliver the record ID and, for changes, the changed property only, not the full record. Pair any trigger with a Get Record action to hydrate the full object.
  • Search has a low, separate rate limit of about 4 requests per second. Heavy search use across many clients reaches it quickly. When HubSpot returns a 429, TaskJuice treats it as a retryable rate-limit error and retries with backoff. The non-search CRM endpoints use HubSpot's higher standard limit.
  • Triggers and actions are in beta. Behavior may change as the integration matures.
  • Upsert is contacts-only. Other object types must use Create Record or Update Record. There is no batch create or update action for arbitrary object types.
  • Webhook subscriptions are not filtered per property at the source. A trigger fires for any matching change. Narrow the events you act on with a downstream Filter or Branch node.
  • Custom objects work without schema introspection. You can target a custom object by typing its objectType, but there is no dropdown that fetches custom-object property schemas, so you supply property names yourself.
  • HubSpot Workflows, Marketing Email, and Forms APIs are not supported. This integration covers CRM objects, associations, notes, lists, and owners only.
Was this helpful?