Skip to content

Connector · CRM and email lists

HubSpot, in every client’s workflows.

Add or update a contact, create a contact, or start when a deal moves to a stage, with the client’s own HubSpot account.

Triggers
3start a workflow
Actions
4steps in a workflow

Start a workflow when something happens in HubSpotBeta

By webhook where HubSpot sends one, by checking where it does not. A webhook is checked once a day to see it is still on, and if HubSpot turns it off the alert carries a Reconnect button.

  • A deal moves to a stagePolledChecked every 5 minutes: a HubSpot private app cannot register a webhook. The token needs crm.objects.deals.read.
  • A new contact is addedPolledA contact created in HubSpot (a form, an import, by hand), checked every 5 minutes. The token needs crm.objects.contacts.read.
  • A support ticket is openedPolledA ticket created in HubSpot, checked every 5 minutes. The token needs the tickets scope.

Do it in HubSpot

A step with its own fields: values from the run go in by name, and what HubSpot answers is there for the next step.

  • Add or update a contactCreates the contact, or updates the one with this email. A lead who submits twice is one contact.
  • Create a contactA new contact. HubSpot refuses a second contact with the same email (409): the run fails and says so.
  • Update a contactChange properties of one contact, found by its id or its email. Properties left out keep their value; a contact that does not exist fails the step.
  • List contactsEvery contact, up to 1,000 (ten pages of 100), with their email, name, phone and company. Past that, the step says it stopped.

Connect the client’s HubSpot

On the client’s page in Thrum: Add credential, type HubSpot private app token.

In the client’s HubSpot: Settings → Integrations → Private Apps (Legacy apps) → Create → scopes crm.objects.contacts.write, and for the triggers crm.objects.contacts.read, crm.objects.deals.read and tickets → copy the access token. A private app needs no HubSpot review.

The key is stored encrypted and bound to that client: another client’s workflow cannot use it, and no template or pack copies it.

HubSpot’s API documentation

Via HTTP

Or by web request: create or update a contact

The lead goes straight into the client’s CRM, and a second enquiry from the same person updates the same contact. The web request step, filled in: paste it, swap in the client’s ids, add their key.

  1. 01

    Add the client’s credential

    On the client’s page in Thrum: Add credential, type API key. In the client’s HubSpot: Settings → Integrations → Private Apps → Create → scope crm.objects.contacts.write → copy the access token.

    {
      "api_key": "pat-…"
    }
  2. 02

    Add a web request step

    Name it “Add to HubSpot”, set it as here, and pick the credential. Values in double braces are read from the run: here, the lead the form brought in.

    {
      "method": "POST",
      "url": "https://api.hubapi.com/crm/v3/objects/contacts/batch/upsert",
      "headers": {
        "Authorization": "Bearer {{ credential.api_key }}"
      },
      "body": {
        "inputs": [
          {
            "idProperty": "email",
            "id": "{{ lead.email }}",
            "properties": {
              "email": "{{ lead.email }}",
              "firstname": "{{ lead.name }}",
              "phone": "{{ lead.phone }}"
            }
          }
        ]
      }
    }
  3. 03

    What goes out, and what comes back

    The whole name goes in First name. Ask for first and last name separately on the form to fill both.

    POST https://api.hubapi.com/crm/v3/objects/contacts/batch/upsert
    content-type: application/json
    authorization: Bearer ••••••••
    
    {
      "inputs": [
        {
          "idProperty": "email",
          "id": "nadia@example.com",
          "properties": {
            "email": "nadia@example.com",
            "firstname": "Nadia Karim",
            "phone": "+447700900222"
          }
        }
      ]
    }
    200
    {
      "status": "COMPLETE",
      "results": [
        {
          "id": "51",
          "new": true,
          "properties": {
            "email": "nadia@example.com",
            "firstname": "Nadia Karim",
            "phone": "+447700900222"
          },
          "createdAt": "2026-09-28T09:05:00.000Z",
          "updatedAt": "2026-09-28T09:05:00.000Z",
          "archived": false
        }
      ],
      "startedAt": "2026-09-28T09:05:00.000Z",
      "completedAt": "2026-09-28T09:05:00.100Z"
    }

Watched like everything else

When HubSpot stops answering or refuses the client’s key, you hear about it, and your client does not.

A failing request
Tried 3 times, 5 seconds apart and doubling, only for errors a retry can fix
A service that asks for a pause
Given it, up to an hour
Requests at once, per account
2, per worker; the rest wait their turn
Timeout
15 seconds, unless the step sets its own
Private and internal addresses
Refused, on every redirect too
The client’s key
Encrypted, bound to the client, and kept out of every run record
A step that keeps failing
Marks the workflow Degraded and alerts you, not the client

HubSpot and its logo are trademarks of their owner, used here only to say what Thrum works with; no endorsement is implied.

Thrum is cooking.

Get early access and you’ll be among the first in. Early members get a launch perk.