HubSpot Connection
Connect to HubSpot to manage CRM objects (contacts, companies, deals, tickets) and drive workflows from HubSpot events via the HubSpot Trigger.
Configuration
| Field | Description | Required |
|---|---|---|
| Private App Access Token | Portal-scoped token used by every action node | Yes |
| Client Secret | Public/developer app's Client Secret; used to verify webhook signatures | Only for the HubSpot Trigger |
| App ID | Numeric ID of your developer app | Only for automatic webhook URL updates |
| Developer API Key | Developer-account-scoped key used to call HubSpot's Webhooks Settings API | Only for automatic webhook URL updates |
The Private App Access Token alone is enough for the action nodes (Contacts, Deals, Companies, Tickets). The other three fields only matter if you also want to use the HubSpot Trigger.
Quick start (action nodes only)
If you only need to read/write CRM objects, you can skip everything below the Access Token row.
- Log in to HubSpot as a super admin.
- Settings (top-right gear) → Integrations → Private Apps → Create a private app.
- Basic Info tab — name your app.
- Scopes tab — add the CRM scopes your workflows need:
crm.objects.contacts.read,crm.objects.contacts.writecrm.objects.companies.read,crm.objects.companies.writecrm.objects.deals.read,crm.objects.deals.write- …and so on for tickets/quotes/etc.
- Create app → Continue creating to confirm.
- Copy the Access Token (starts with
pat-na1-...orpat-eu1-...) into the connection. - Save.
Adding HubSpot Trigger support
The HubSpot Trigger fires on CRM events your developer app subscribes to (e.g. contact.creation, deal.propertyChange). To make it work end-to-end, HubSpot needs to know where to POST those events. The connection supports two ways to set that URL:
Option A — Automatic (recommended)
You provide the connection with an App ID + Developer API Key. On save, the backend calls PUT /webhooks/v3/{appId}/settings to point HubSpot's webhook delivery at this connection's callback URL. Re-seeds and WEBHOOK_BASE_URL changes are automatically picked up.
Setup:
- Create a developer app (a different app type from the Private App above):
- Go to https://developers.hubspot.com → log in with your developer account.
- Apps → Create app.
- App Info tab — name, description, logo.
- Auth tab — copy the Client ID and Client Secret. The Client Secret goes into the connection.
- Webhooks tab — skip URL configuration for now; the backend will set it.
- App Info tab → copy the App ID (a numeric value) into the connection.
- Developer API Key:
- Still on https://developers.hubspot.com → click your developer account name (top-right) → Account (or Profile & Preferences) → API Key tab.
- Generate Key or copy the existing one. This is account-level, not app-level — one key works for every developer app you own.
- Paste into the connection's Developer API Key field.
- Save the connection. Status switches to
activeand HubSpot's webhook target URL is now:<WEBHOOK_BASE_URL>/api/conn-webhook/<connection-webhook-token> - Subscribe to events (still in the HubSpot developer dashboard, since subscriptions are semantic and we don't touch them):
- Your app → Webhooks tab → Create subscription.
- Pick the event type your trigger workflow filters on (e.g.
contact.creation). - Save.
- Install the developer app on the test portal:
- On the developer dashboard click your app → Install URL (OAuth).
- Visit the URL in a browser; HubSpot prompts you to install on a portal of your choice. This is the portal whose events you'll receive.
Developer key vs Private App token
The two HubSpot credentials this connection holds look similar but are scoped completely differently:
- Private App Access Token (
pat-na1-...) — portal-scoped. Lets us read/write CRM data inside that portal. One per portal. - Developer API Key — developer-account-scoped. Lets us manage developer apps you own (including webhook settings). One per developer account, covers every app you own.
You need both when using the trigger.
Option B — Manual (paste the URL yourself)
If you can't generate a Developer API Key (e.g. you don't own the developer account), the trigger still works — just leave App ID and Developer API Key blank.
Setup:
- Save the connection with only Access Token + Client Secret. Status will be
pending_manual_setup. - Find the webhook URL — either from the connection's Webhook URL display in the UI, or:bash
curl -H "Authorization: Bearer $TOKEN" \ https://<your-deployment>/api/connections/<connection-id>/webhook-info \ | jq '.data.url' - Open your developer app → Webhooks tab → paste the URL into Target URL and save.
- Add event subscriptions (e.g.
contact.creation).
Trade-off vs Option A: if the webhook token changes (re-seed, environment swap), you have to repeat steps 2–3.
Required scopes (action nodes)
The Private App's scopes determine which action nodes work. Common picks:
| Action | Scope |
|---|---|
| Contacts (read/write) | crm.objects.contacts.read, crm.objects.contacts.write |
| Companies | crm.objects.companies.read, crm.objects.companies.write |
| Deals | crm.objects.deals.read, crm.objects.deals.write |
| Tickets | crm.objects.tickets.read, crm.objects.tickets.write |
For the developer app (Trigger side), only the Webhook scope and the per-event scopes (e.g. crm.objects.contacts.read) are needed.
Self-fire & loop hazard
HubSpot fires webhook events for ANY change on a subscribed object — including changes made via the same app's API calls. That means:
- An action workflow that creates a contact via the Contacts node will fire
contact.creationback to the HubSpot Trigger workflow on the same connection. This is useful forintegrations:testself-loops. - A trigger workflow that filters on
contact.creationAND creates another contact in response → infinite loop.
Mitigations:
- End trigger workflows in non-creating nodes (a
switchwith no rules, a datastore write, an email send) — the bundled fixture uses a no-op switch for this reason. - Or filter on
contact.propertyChangefor a specific property the trigger workflow doesn't touch.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
connection_test failed: ... 401 on save | Access Token wrong, revoked, or scope mismatch | Regenerate the Private App access token, double-check selected scopes. |
Status pending_manual_setup after saving with App ID + Developer Key | App ID isn't numeric, or Developer Key invalid | App ID is from the developer app's Basic Info page (a number like 1234567). Developer Key is from your developer account → Account → API Key. |
webhook_status=error with 403 / scope insufficient | Developer Key was generated by an account that doesn't own this app | Use the API Key from the developer account that owns this app. One account, many apps. |
invalid_url or URL must be HTTPS on save | WEBHOOK_BASE_URL isn't HTTPS or isn't publicly reachable | Set WEBHOOK_BASE_URL to a public HTTPS endpoint (Cloudflare tunnel in dev) and re-save. |
| Trigger workflow never fires after a real change | App not installed on this portal, or wrong event subscribed | Re-visit the developer app's Install URL (OAuth) for this portal; verify subscriptions cover the event your trigger filters on. |
Usage
Once created, this connection is available to:
- HubSpot action nodes
- HubSpot Trigger
TIP
Private app tokens inherit the scopes you select during creation. Add only what your workflows actually need to keep blast radius small.