HubSpot
Connect HubSpot with a private app token, import lists with a field mapping, log sends and replies on the contact, and keep unsubscribes in step both ways.
The HubSpot integration does four things. It imports HubSpot contacts into a SendCanyon list, once or on a schedule. It logs activity on the HubSpot contact: every send and reply as an email, and every bounce and unsubscribe as a note. It can set lifecycle stage and lead status when a contact replies, bounces or unsubscribes. And it syncs unsubscribes both ways.
1. Create a HubSpot private app
SendCanyon connects with a private app access token from your own portal. There is no marketplace app to install. You need to be a HubSpot super admin to create one.
In HubSpot, open Settings → Integrations → Private Apps and choose Create a private app. Some newer portals list private apps under Development → Legacy apps instead; it is the same thing.
Name it (for example "SendCanyon") and open the Scopes tab.
Tick the four required scopes below, plus the optional one if you want SendCanyon unsubscribes to opt the contact out in HubSpot.
Create the app, then copy the access token (it starts with
pat-).
| Scope | Required | What SendCanyon uses it for |
|---|---|---|
| crm.objects.contacts.read | Yes | Look up contacts by email, read list members, check for opt-outs |
| crm.objects.contacts.write | Yes | Create missing contacts, set lifecycle stage and lead status, log emails and notes |
| crm.lists.read | Yes | Show your HubSpot lists and read their members |
| crm.schemas.contacts.read | Yes | List contact properties for the field mapping and the status options |
| communication_preferences.write | Optional | Opt a contact out of all email in HubSpot when they unsubscribe from SendCanyon |
2. Connect
In SendCanyon go to Settings → Integrations → HubSpot. Paste the token into Private app access token and choose Connect HubSpot. SendCanyon checks the token with HubSpot before saving it. It confirms the token is valid, reads which portal it belongs to, and checks every required scope. If a scope is missing, nothing is saved and the panel lists each scope to tick, with what it is needed for. After you add scopes in HubSpot, paste the token again.
Once connected, the panel shows the portal ID, its HubSpot domain and data region. The token is stored encrypted and is never shown again. Test re-checks the token and scopes, then reads a contact, a list and the contact properties, and shows a line for each check. Replace token swaps in a new token, for example after rotating it in HubSpot.
3. Import contacts from HubSpot
Under Import from HubSpot, choose New import, then:
- Import: pick A HubSpot list (any contact list, static or active), or Contacts matching a property. The property filter supports is, is not, contains, is known and is unknown.
- Into SendCanyon list: a New list (named after the HubSpot list by default) or an Existing list.
- Field mapping: email is always HubSpot's
email. First name, last name, company and job title default tofirstname,lastname,companyandjobtitle. Phone defaults tophoneand lands in the custom fieldphone. Set any row to Don't import. Map another property to a custom field copies any HubSpot property into a custom field you name, usable as a merge tag in templates. - Re-sync: Manual only, Every hour or Every day.
Import now saves the import and starts it in the background. Each import shows its progress as it runs: how many contacts were read, how many are new, updated, skipped and suppressed. HubSpot contacts go through the same pipeline as a CSV import:
- Contacts are deduplicated by email, ignoring case. A contact already in the workspace is updated, not duplicated.
- A blank HubSpot field never erases a value already in SendCanyon. Custom fields are merged, not replaced.
- Records without a valid email are skipped.
- An address on your suppression list is still added to the list, marked suppressed, and never sent to.
- Your plan's contact limit applies. An import that would exceed it fails with the same message a CSV import shows.
Scheduled re-syncs add and update contacts. They never remove anyone: a contact taken off the HubSpot list stays in the SendCanyon list. You can change an import's schedule, run it with Import now, or remove it; contacts it already imported stay. Scheduled re-syncs don't send "import finished" notifications; check the sync log instead.
4. Activity sync
Under Activity sync, each event can be switched on or off:
| SendCanyon event | What appears on the HubSpot contact |
|---|---|
| Email sent | An email (outgoing) with the subject, the email text, and a line naming the campaign and step |
| Reply received | An email (incoming) with the reply text, plus the replied status mapping |
| Email bounced | A note with the bounce type and reason, plus the bounced status mapping |
| Contact unsubscribed | A note, the unsubscribed status mapping, and an email opt-out if enabled (see below) |
Activity is matched to the HubSpot contact by email. With Create the HubSpot contact if it doesn't exist on (the default), a missing contact is created with the email, name, company and job title SendCanyon has. With it off, the event is skipped and the sync log says so. If HubSpot refuses to create an email record for your app, the same content is logged as a note so nothing is lost. Activity is logged once per event, even when a delivery is retried.
5. Lifecycle stage and lead status
Under Lifecycle stage and lead status, choose what to set When a contact replies, When an email bounces and When a contact unsubscribes. For example, set lead status to Connected on reply. The options are read from your portal, so custom stages and statuses appear. No change leaves a field alone.
6. Unsubscribe sync
- SendCanyon → HubSpot. A SendCanyon unsubscribe always logs a note on the contact. When Opt unsubscribes out of all email in HubSpot is on and the app has
communication_preferences.write, the contact is also opted out of all email in HubSpot, so its Unsubscribed from all email property is set. Without the scope, the panel and sync log say the opt-out was not mirrored. - HubSpot → SendCanyon. With Suppress contacts who opt out in HubSpot on, SendCanyon checks HubSpot every 15 minutes for contacts marked Unsubscribed from all email. Each one is added to your suppression list as an unsubscribe, noted "Opted out in HubSpot". The first check picks up everyone already opted out. Sync opt-outs now runs a check straight away.
- Opt-outs only ever add suppressions. A re-subscribe on either side is not copied, because the other system cannot see the consent behind it. An existing suppression, such as a spam complaint, is never overwritten.
Rate limits
HubSpot allows a private app 100 requests every 10 seconds, and 5 per second on search. SendCanyon stays under that: at most 90 requests per 10 seconds and 4 searches per second per token, across all its servers. On a 429, SendCanyon waits as long as HubSpot's Retry-After header asks and tries again. A long wait, such as a daily limit, is rescheduled rather than retried straight away. Temporary HubSpot errors are retried with backoff, up to six times for activity. Large imports take longer as a result, but nothing is dropped.
Troubleshooting
Each entry is a message the HubSpot panel or its sync log can show, followed by what to do.
- Paste the private app access token. / That does not look like a HubSpot access token. Copy the whole token from the private app's Auth tab. It starts with
pat-. - HubSpot rejected the access token. It may have been rotated or the private app deleted. The token is wrong, was rotated, or the private app was deleted. Copy the current token and use Replace token.
- HubSpot accepted the token, but the private app is missing scopes: Tick … — needed to … Tick each listed scope in the private app, save, then paste the token again. HubSpot may issue a new token when scopes change.
- Integrations are included on the … plan. Upgrade to connect Slack, Zapier and HubSpot. Your plan doesn't include integrations. Use the upgrade button.
- Syncing is paused: your plan does not include integrations. The workspace moved to a plan without integrations. Upgrade, and syncing resumes with your settings intact.
- HubSpot is rate limiting this app. Try again in a minute. Something else is using this private app's allowance too. Wait and retry; background syncs retry by themselves.
- Could not reach HubSpot. / HubSpot 5xx: … HubSpot is having trouble. Try again shortly; background syncs retry by themselves.
- Needs attention (status), with an error underneath The last sync hit an authentication or scope error. Fix the token or scopes, then run Test. The status clears on the next success.
- Unsubscribes are logged as notes but not mirrored into HubSpot's email opt-out Add
communication_preferences.writeto the private app and paste the token again. - This import is already running. / An opt-out sync is already running. Wait for the current run to finish. Its progress is on the import and in the sync log.
- An import failed with a message about your plan's contact limit The import would take the workspace past its contact limit. Upgrade, or import a smaller list.
- Skipped: this workspace's plan does not include integrations. A run was queued before a downgrade. Nothing was imported.
- Sync log: Not in HubSpot; creating contacts is switched off. Turn on Create the HubSpot contact if it doesn't exist, or add the contact in HubSpot.
- Sync log: Logged as a note: HubSpot refused an email engagement for this app. Nothing to do. The activity is on the contact as a note. Your portal restricts email records for this app.
- Sync log: Lifecycle stage left at "…": HubSpot does not move a stage backwards. Expected: the contact is already at a later stage than the mapping sets.
- Sync log: Not mirrored: the private app lacks communication_preferences.write. Add the optional scope and reconnect, or ignore it if you don't want HubSpot opt-outs.
Disconnecting
Disconnect (type HubSpot to confirm) deletes the stored token, removes saved HubSpot imports and stops all syncing straight away, including retries already queued. Contacts, lists and suppressions already in SendCanyon, and activity already logged in HubSpot, stay where they are. To fully revoke access, also delete the private app in HubSpot.
Was this page helpful?
Related articles
- SlackPost replies, bounces, unsubscribes, campaign updates and a daily digest to Slack channels through incoming webhooks.Integrations
- ZapierStart Zaps from replies, sends, opens, clicks, bounces, unsubscribes, completed campaigns and new contacts, and create contacts, tag them, add them to lists and campaigns from any app.Integrations
- Quick start: zero to first campaignThe six steps between creating a workspace and launching your first sequence, and how long each one really takes.Getting Started