Skip to main content
HubSpot The HubSpot connector provides read/write access to a HubSpot portal through the HubSpot REST API. It can be used either as a Builder app (automations call HubSpot instructions directly) or as a remote MCP server consumed by an AI agent. Two authentication modes coexist on the same MCP endpoint:
  • Central OAuth2 (recommended) — one HubSpot Public App is registered once by the Prisme.ai workspace admin; every end user signs in with their own HubSpot portal. Nothing to install per tenant. Requires the platform admin to grant the HubSpot capability in Prisme.ai Governance (see below).
  • Tenant PAT — install the HubSpot app in your workspace and paste a Private App access token. Shared across the workspace’s users; no per-user sign-in.
The connector exposes ~120 operations grouped into 18 entity tools covering the CRM (contacts, companies, deals, tickets, engagements, associations, pipelines, properties, owners, lists) and the Marketing layer (forms, marketing emails, workflows, files).

CRM Records

Contacts, companies, deals and tickets with list/search/get/create/update/archive plus batch and merge operations

Engagements & Pipelines

Notes, tasks, calls, emails and meetings; pipelines and stages; properties and property groups; owners and lists

Central OAuth or PAT

One shared HubSpot Public App with per-user sign-in, or a tenant-level Private App Token — both modes coexist on the same MCP endpoint

Prerequisites

  • A HubSpot account with access to the portal you want to expose.
  • For the central OAuth mode — the platform admin has registered ONE HubSpot Public App through the HubSpot Developer Platform 2025.2 (CLI Projects), declared the OAuth scopes the connector needs, allowlisted the portals that can install it (Private distribution caps at 10 portals; Solution Partners get 100), and stored its Client ID + Client Secret in the Secrets of the central hubspot workspace. The end user only needs to click Connect once and select their portal on the HubSpot consent screen.
  • For the tenant PAT mode — a Private App access token created at HubSpot Settings → Integrations → Private Apps (https://app.hubspot.com/private-apps/<portal-id>), with the scopes covering the resources you intend to read/write (crm.objects.contacts.*, crm.objects.companies.*, tickets, content, automation, forms, files, etc.), pasted into the installed app instance.
  • Base URL (default: https://api.hubapi.com).
The two modes are mutually exclusive per MCP call: callers identify themselves either by being authenticated to Prisme.ai (central) or by sending the mcp-api-key header (tenant). The same workspace can serve both at the same time.
HubSpot has no standard RFC 7009 revocation endpoint. The disconnect tool deletes the platform-stored tokens but cannot revoke them at HubSpot — refresh tokens may still be valid until they naturally expire (typically 6 months idle).

Installation

  1. Go to Apps in your workspace
  2. Search for HubSpot and install it
  3. Open the app instance configuration and fill in either the PAT or the OAuth client credentials

Configuration

FieldDescription
HubSpot API Base URLBase URL of the HubSpot API (default https://api.hubapi.com)
HubSpot Private App Token (PAT)Private App access token for this tenant — shared across the tenant’s users. Required for tenant-mode access (header mcp-api-key). Leave empty to use the central OAuth shared by the platform admin.
MCP EndpointAuto-populated on install — URL of the MCP endpoint for this instance. Pass header mcp-api-key to use tenant PAT mode; omit the header to use shared OAuth (user-delegated, central).
MCP API KeyAuto-populated on install — signed key used in the mcp-api-key header (tenant PAT mode). Do not modify.
OAuth credentials (Client ID / Client Secret / authorization URL / token URL / scopes) are NOT part of the app instance config anymore — they live in the Secrets of the central hubspot workspace and are shared by all callers in central mode. See the Setup (one-time, platform admin) section above.

Available Instructions

Every instruction resolves credentials from the workspace configuration. CRM list operations accept limit (default 100) and after for cursor pagination, plus properties to request specific fields. Most CRM tools accept an optional objectType to override the default object type — useful for custom objects.

Contacts

InstructionArguments
listContactslimit, after, properties, propertiesWithHistory, associations, archived
getContactcontactId*, properties, propertiesWithHistory, associations, archived, idProperty
createContactproperties*, associations
updateContactcontactId, properties, idProperty
archiveContactcontactId*
searchContactsfilterGroups, sorts, query, properties, limit, after
mergeContactsprimaryObjectId, objectIdToMerge
batchReadContactsinputs*, properties, propertiesWithHistory, idProperty
batchCreateContactsinputs*
batchUpdateContactsinputs*
batchArchiveContactsinputs*

Companies

Same shape as contacts: listCompanies, getCompany, createCompany, updateCompany, archiveCompany, searchCompanies, mergeCompanies, batchReadCompanies, batchCreateCompanies, batchUpdateCompanies, batchArchiveCompanies.

Deals

Same shape as contacts: listDeals, getDeal, createDeal, updateDeal, archiveDeal, searchDeals, mergeDeals, batchReadDeals, batchCreateDeals, batchUpdateDeals, batchArchiveDeals.

Tickets

listTickets, getTicket, createTicket, updateTicket, archiveTicket, searchTickets, batchReadTickets, batchCreateTickets, batchUpdateTickets, batchArchiveTickets (no merge).

Associations

InstructionArguments
listAssociationsfromObjectType, fromObjectId, toObjectType*, after, limit
createAssociationfromObjectType, fromObjectId, toObjectType, toObjectId, associationCategory, associationTypeId
archiveAssociationfromObjectType, fromObjectId, toObjectType, toObjectId

Engagements

Notes, tasks, calls, emails and meetings share the same shape: list, get, create, update, archive.
InstructionArguments
listNotes / listTasks / listCalls / listEmails / listMeetingslimit, after, properties, associations, archived
getNote / getTask / getCall / getEmail / getMeetingengagementId*, properties, associations, archived
createNote / createTask / createCall / createEmail / createMeetingproperties*, associations
updateNote / updateTask / updateCall / updateEmail / updateMeetingengagementId, properties
archiveNote / archiveTask / archiveCall / archiveEmail / archiveMeetingengagementId*

Pipelines

InstructionArguments
listPipelinesobjectType*
getPipelineobjectType, pipelineId
createPipelineobjectType, label, stages*, displayOrder
updatePipelineobjectType, pipelineId, label, stages, displayOrder
archivePipelineobjectType, pipelineId
listPipelineStagesobjectType, pipelineId
getPipelineStageobjectType, pipelineId, stageId*
createPipelineStageobjectType, pipelineId, label*, metadata, displayOrder
updatePipelineStageobjectType, pipelineId, stageId*, label, metadata, displayOrder
archivePipelineStageobjectType, pipelineId, stageId*

Properties

listProperties, getProperty, createProperty, updateProperty, archiveProperty, listPropertyGroups, createPropertyGroup, updatePropertyGroup, archivePropertyGroup.

Owners

InstructionArguments
listOwnersemail, after, limit, archived
getOwnerownerId*, idProperty

Lists

InstructionArguments
createListname, objectTypeId, processingType*, filterBranch
getListlistId*, includeFilters
updateListlistId*, name
deleteListlistId*
searchListsquery, count, offset, processingTypes, additionalProperties
addMemberslistId, recordIds
removeMemberslistId, recordIds
getMembershipslistId*, after, limit

Forms

InstructionArguments
listFormsafter, limit, archived, formTypes
getFormformId*, archived
createFormname, formType, fieldGroups, configuration
updateFormformId*, name, fieldGroups, configuration
archiveFormformId*
submitFormportalId, formGuid, fields*, context, legalConsentOptions

Marketing Emails

InstructionArguments
listMarketingEmailsafter, limit, archived, sort, name
getMarketingEmailemailId*
createMarketingEmailname*, subject, subscription, content
updateMarketingEmailemailId*, name, subject, subscription, content
archiveMarketingEmailemailId*
sendTransactionalemailId, message, contactProperties, customProperties

Workflows

InstructionArguments
listWorkflowslimit, offset
getWorkflowworkflowId*
enrollContactInWorkflowworkflowId, email
unenrollContactFromWorkflowworkflowId, email

Files

InstructionArguments
listFilesafter, limit, parentFolderId, parentFolderPath, name, extension
getFilefileId*
getSignedUrlfileId*, expirationSeconds, upscale
archiveFilefileId*
importFromUrlname, url, folderId, folderPath, access, duplicateValidationStrategy
listFoldersafter, limit, parentFolderId, name
createFoldername*, parentFolderId, parentPath
archiveFolderfolderId*
Arguments flagged with * are required.

DSUL Examples

Look up a contact by email

- Hubspot.contacts:
    action: search
    filterGroups:
      - filters:
          - propertyName: email
            operator: EQ
            value: '{{lead.email}}'
    properties:
      - email
      - firstname
      - lastname
      - lifecyclestage
    limit: 1
    output: matched

Create a deal and associate it to a company

- Hubspot.deals:
    action: create
    properties:
      dealname: '{{opportunity.name}}'
      amount: '{{opportunity.amount}}'
      dealstage: 'appointmentscheduled'
      pipeline: 'default'
      closedate: '{{opportunity.closeDate}}'
    associations:
      - to:
          id: '{{companyId}}'
        types:
          - associationCategory: HUBSPOT_DEFINED
            associationTypeId: 5
    output: created

Add a contact to a static list

- Hubspot.lists:
    action: addMembers
    listId: '{{leadsListId}}'
    recordIds:
      - '{{contactId}}'

Send a transactional email

- Hubspot.marketingEmails:
    action: sendTransactional
    emailId: '{{templateId}}'
    message:
      to: '{{lead.email}}'
      from: 'noreply@acme.com'
    contactProperties:
      firstname: '{{lead.firstName}}'
    customProperties:
      orderId: '{{order.id}}'
      orderTotal: '{{order.total}}'

Bulk-import contacts

- Hubspot.contacts:
    action: batchCreate
    inputs:
      - properties:
          email: 'alice@acme.com'
          firstname: 'Alice'
          lastname: 'Doe'
      - properties:
          email: 'bob@acme.com'
          firstname: 'Bob'
          lastname: 'Smith'
    output: batchResult

Error Handling

HTTP StatusMeaningTypical Cause
400Bad RequestInvalid property value, malformed filterGroups, missing required field
401UnauthorizedMissing / invalid PAT or OAuth token, revoked refresh token
403ForbiddenThe token does not include the required scope, or the user/portal does not have the feature enabled (Marketing Hub Pro+, etc.)
404Not FoundRecord / list / workflow / form does not exist (or was archived)
409ConflictUnique-property collision (e.g. contact with the same email already exists)
429Rate LimitedPer-portal quota exceeded — back off based on the X-HubSpot-RateLimit-Secondly-Remaining headers
500 / 502 / 503Server ErrorTransient HubSpot API error — retry with exponential backoff

Common Issues

“Authentication required: please sign in to Prisme.ai before calling the HubSpot MCP without an mcp-api-key header” — A caller hit the central endpoint without a valid Prisme.ai session AND without an mcp-api-key. Either sign in to Prisme.ai (central mode) or pass the tenant mcp-api-key (tenant mode). “Central OAuth config missing” — The hubspotOauthClientId / hubspotOauthClientSecret secrets of the central hubspot workspace are empty. Ask the platform admin to complete the Setup (one-time, platform admin) section above. “HubSpot capability not granted” — The current user is signed in to Prisme.ai but has not been granted the HubSpot capability in Governance. Ask the platform admin. “Invalid mcp-api-key” (tenant mode) — The mcp-api-key header does not match the central app secret. Reinstall the app instance to regenerate a signed key. “This HubSpot tenant has no Personal Access Token configured” — Tenant mode was used (mcp-api-key header present) but the app instance’s PAT field is empty. Either fill the token or drop the header to fall back to central OAuth. invalid_scope / “domain mismatch” during the OAuth dance — The OAuth URL requests a scope that the deployed HubSpot Public App does not declare. HubSpot OAuth requires scope= (mandatory) and optional_scope= (best-effort) to be split, and every requested scope to appear in either requiredScopes or optionalScopes of app-hsmeta.json. Edit both sandbox/src/app/app-hsmeta.json AND prod/src/app/app-hsmeta.json, then hs project upload && hs project deploy for each. redirect_uri_mismatch during the OAuth dance — The redirect URI generated by the connector (<api-url>/workspaces/slug:hubspot/webhooks/oauthCallback) is not in the deployed HubSpot app’s redirectUrls. Edit app-hsmeta.json and re-deploy. “The app could not be installed because the app developer has not signed the acceptable use policy” — Only happens with distribution: marketplace apps. The shipped projects use distribution: private to bypass this requirement (capped at 10 allowlisted portals). If you switch to marketplace later, sign the AUP from the HubSpot developer dashboard before the first install. MISSING_SCOPES (403) — The user’s portal subscription does not include the feature the operation needs (Marketing Hub Pro+, CMS Hub, etc.), or the user did not grant the corresponding optional scope. Some scopes are only available on paid HubSpot tiers — the connector keeps them in optionalScopes so they degrade gracefully on Free / Starter portals. OBJECT_ALREADY_EXISTS on contact create — A contact with the same email already exists. Either update the existing contact (use email as idProperty) or query first with search. Lists API: cannot add members to a dynamic list — Only static / MANUAL lists accept addMembers and removeMembers. Dynamic lists are managed by their filter criteria. Central OAuth — disconnecting a user — In central mode, the agent calls the disconnect tool (or the user opens <api-url>/workspaces/slug:hubspot/webhooks/disconnectOAuth) to delete the stored tokens. HubSpot does not expose an RFC 7009 revocation endpoint, so the refresh tokens may still be valid at HubSpot until they naturally expire (typically 6 months idle).

External Resources

HubSpot Developer Docs

Official HubSpot REST API reference

HubSpot Developer Platform 2025.2

Build, deploy and manage HubSpot Public Apps via the CLI Projects framework

HubSpot OAuth scopes

Required vs optional scopes, scope-tier matrix, scope group reference

Tool Agents

Build AI agents that call MCP tools dynamically