---
title: "Linkbreakers + HubSpot: QR lead capture and CRM sync"
description: "Connect HubSpot with a service key and every person who scans your QR codes and gives their email or phone becomes a HubSpot contact, with their form answers in contact properties, added to a static list, optionally with a deal in your pipeline, and subscribed to marketing email only with their consent. Setup, scopes, what is synced, and the Assistant and MCP tools."
canonical: "https://linkbreakers.com/help/article/linkbreakers-hubspot-integration-qr-lead-capture-and-crm-sync"
last-updated: 2026-11-09
---

# Linkbreakers + HubSpot: QR lead capture and CRM sync

> Connect HubSpot with a service key and every person who scans your QR codes and gives their email or phone becomes a HubSpot contact, with their form answers in contact properties, added to a static list, optionally with a deal in your pipeline, and subscribed to marketing email only with their consent. Setup, scopes, what is synced, and the Assistant and MCP tools.

:::try-ai-prompt {"prompt":"Connect HubSpot with my service key, add synced contacts to my Trade show leads list, create a deal in the first stage of my Sales pipeline for each one, and subscribe only people who ticked my Consent field","description":"Connect HubSpot with the Assistant.","target":"assistant"}:::

## Short answer

Linkbreakers connects to HubSpot directly. In the dashboard, open **Integrations**, pick **HubSpot**, paste a HubSpot service key and select **Connect**. From then on, every person who goes through one of your links or QR codes and whose email or phone Linkbreakers knows, for example after a lead form, is created or updated as a HubSpot contact, with their name, phone and form answers in contact properties. You can add them to a static list, have Linkbreakers create a deal for each one in the pipeline stage you choose, and subscribe to marketing email only the people who gave their consent.

No Zapier, Make or webhook is needed. The integration is available on every plan.

## Quick summary

- Connect once per workspace with a service key (`pat-na1-...`, `pat-na2-...`, `pat-eu1-...`), or a private app token on older accounts
- Contacts are created or updated, matched on email, or on phone when there is no email
- Visitors known only by their phone number are synced too
- Form answers go to writable contact properties, by internal name
- Optionally added to one static contact list
- Optionally a deal in a pipeline stage, one open deal per contact
- Marketing consent subscribes the email to your portal's marketing subscription type, never over an opt-out; a new contact without consent is unsubscribed from it
- Only people's visits: bots, link previews and AI agents never become contacts
- Also set up from the Assistant, the MCP server or the REST API

## How it works

A contact is synced when a visitor goes through a step of a link's workflow and Linkbreakers knows their email or phone. That is usually right after a [lead form](/help/article/how-to-add-a-lead-capture-form-to-a-qr-code), but it can also come from the chat bot or any step that saves visitor data. Linkbreakers sends the contact to HubSpot from its servers, once per step, at the moments the connection covers (all of them by default).

With an email, the contact is created or updated on that email. A visitor known only by phone updates the contact whose phone or mobile phone matches, or creates a new one. Then Linkbreakers adds the contact to your list, creates its deal if you asked for one, and last records the consent, so a consent that cannot be recorded never stops the contact from syncing.

## Connect HubSpot

1. In HubSpot, open **Development > Keys > Service Keys** and select **Create service key**. (Older accounts can still use a private app under **Development > Legacy Apps**; HubSpot replaced private apps with service keys in October 2026.)
2. Give it these scopes:
   - `crm.objects.contacts.read` and `crm.objects.contacts.write`
   - `crm.schemas.contacts.read`
   - `crm.lists.read` and `crm.lists.write`
   - `crm.objects.deals.read` and `crm.objects.deals.write`, only to create deals
   - `communication_preferences.read_write`, to subscribe visitors who gave their marketing consent and unsubscribe new contacts who did not
3. Create the key, then copy it (**Show**, then **Copy**).
4. In Linkbreakers, open **Integrations** in the dashboard and pick **HubSpot**.
5. Paste the key in **HubSpot service key or private app token** and select **Connect**. Linkbreakers checks it against HubSpot before storing it.
6. Under **Add contacts to a list**, choose a static list, or **No list: contacts only**.
7. Set the options and the delivery setting below, then save.

The token is encrypted when it is stored and never shown again; the page shows the HubSpot portal ID it belongs to, or the start of the token.

## What gets synced

| Linkbreakers | HubSpot |
|---|---|
| Email | Contact email (the match) |
| Phone | Phone number |
| First name, last name | First name, last name |
| Form answers and other visitor data | Writable contact properties with the same internal name, or the one you map them to |
| The list you chose | Static list membership |
| Deal (optional) | A deal in the chosen pipeline stage, associated with the contact |
| Marketing consent (optional) | Subscribed to the portal's marketing email subscription type |

HubSpot properties have an internal name in snake case, such as `company_size`. An answer goes to the property with the same internal name. Create properties under **Settings > Properties > Contact properties**, or map an answer to an existing one on the HubSpot page. Text, number, date, and single checkbox properties are written; dropdowns and other enumerations, file properties and calculated properties are left out. **Test connection** lists the property names Linkbreakers can write to.

Only static lists are offered. Active lists are filled by their own filters in HubSpot, so nothing can be added to them.

## Options

**Deals.** Choose **The contact and a deal**, then the pipeline and stage. The deal is named `{link}: {name}` unless you set another title, where `{link}` is the name of the link the person came through and `{name}` their name or email. A visitor is synced at each step of a flow, but your sales team wants one deal per person, so no deal is created while the contact has an open deal. Once it is won or lost, a new visit creates a new one. HubSpot leads need Sales Hub seats, so Linkbreakers creates deals, not leads.

**Marketing consent.** Choose the answer where people agree to hear from you: the **Linkbreakers consent** (a Consent field on your form, or the marketing consent goal of the [chat bot](/help/article/how-to-add-an-ai-chat-bot-to-a-qr-code)), or any other answer, such as a checkbox of your own. You can also tick **Add to the list only those who consented**.

HubSpot has no tags, and its double opt-in is a portal setting the API does not drive, so neither option is shown for HubSpot.

## Marketing consent in HubSpot

When a visitor said yes, Linkbreakers subscribes their email to your portal's marketing email subscription type (an active email type meant for marketing, else the default one), with the legal basis "consent with notice". Someone already subscribed is left as they are. Someone who unsubscribed or opted out of all email is never subscribed again: HubSpot refuses it, and Linkbreakers does not count that as a failure.

Without consent, a contact that already existed in HubSpot keeps its subscriptions as they are. Many portals subscribe every new contact to marketing on their own, so a contact Linkbreakers creates without consent is unsubscribed from that marketing type, and nobody becomes mailable without agreeing. HubSpot then does not let a later consent subscribe that contact again through its API: they can still subscribe through one of your own HubSpot forms or emails. A token without `communication_preferences.read_write` still syncs the contact; the page then says only the consent was not recorded.

The Linkbreakers consent field is never pre-ticked, and each answer is kept on the visitor's profile with the wording they agreed to and when.

## Which visitors and which links

The HubSpot page has the same three settings as the other Linkbreakers integrations:

- **Where**: every link, or only some links, directories and tags
- **When**: the moments of a visit (Entry, Interaction, Routing, Exit), or specific steps
- **What is sent**: all visitor data, only some, or just the visit. Email and phone are always sent

Only visits by people are synced. Visits past your plan's tracked visits allowance are not synced.

## Set it up from the Assistant, MCP or the API

**Assistant**: in the dashboard, ask "Connect HubSpot with my service key and create a deal in my Sales pipeline for each new contact".

**MCP server**: an agent connected to the [Linkbreakers MCP server](/help/article/mcp-server-setup) has `contact_integration_connect`, `contact_integration_lists`, `contact_integration_pipelines`, `contact_integration_fields`, `contact_integration_update`, `contact_integration_test`, `contact_integration_get`, `contact_integrations_list` and `contact_integration_disconnect`, with the tool `CONTACT_TOOL_HUBSPOT`.

**REST API**, with a token that has the `integrations:write` scope:

```bash
curl -X POST https://api.linkbreakers.com/v1/integrations/contacts/CONTACT_TOOL_HUBSPOT/connect \
  -H "Authorization: Bearer $LINKBREAKERS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"apiKey": "pat-eu1-..."}'

curl https://api.linkbreakers.com/v1/integrations/contacts/CONTACT_TOOL_HUBSPOT/pipelines \
  -H "Authorization: Bearer $LINKBREAKERS_TOKEN"

curl -X PATCH https://api.linkbreakers.com/v1/integrations/contacts/CONTACT_TOOL_HUBSPOT \
  -H "Authorization: Bearer $LINKBREAKERS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"options": {"consentAttributeKey": "$marketingConsent", "recordKind": "CONTACT_RECORD_KIND_DEAL", "pipelineId": "default", "stageId": "appointmentscheduled"}}'
```

## When to use HubSpot workflows or webhooks

The native connection writes contacts, list memberships, deals and marketing subscriptions. To enroll contacts in sequences, assign owners, or notify reps, build a HubSpot workflow that starts when a contact joins your list or a deal is created. For objects the connection does not write, such as companies or tickets, send [Linkbreakers webhooks](/help/article/how-do-webhooks-work-in-linkbreakers) to Zapier, Make or n8n.

## Limits and caveats

- **One HubSpot portal and one list per workspace**
- **Static lists only**, since active lists fill themselves
- **Properties must exist** with a writable type, or the answer is left out
- **One open deal per contact**, by design; no leads
- **No retries.** A contact HubSpot refuses is reported as the last error on the page, not sent again
- **One way.** Nothing is read back from HubSpot but lists, properties and pipelines

## Frequently asked questions

### Do I still need Zapier to send QR code leads to HubSpot?

No. Linkbreakers creates and updates HubSpot contacts, list memberships and deals directly with a service key.

### Which scopes does the service key need?

Contacts read and write, contact schemas read, and lists read and write. Add deals read and write to create deals, and `communication_preferences.read_write` to subscribe consenting visitors.

### Will someone who unsubscribed in HubSpot be subscribed again?

No. HubSpot refuses to subscribe someone who opted out, and Linkbreakers leaves them as they are.

### Will a visitor who fills two forms create two deals?

No. While the contact has an open deal, no new one is created.

### What happens when I disconnect HubSpot?

Visitors stop being synced and the stored token is deleted. Contacts and deals already in HubSpot stay there.

## Sources

- Linkbreakers HubSpot integration page, API and MCP tools, checked in the product on 2026-11-09.
- HubSpot API documentation: https://developers.hubspot.com/docs/api

## Last reviewed

2026-11-09 by Laurent Schaffner.
