Skip to content

HubSpot Service Hub

Works with: HubSpot Service Hub (tickets). What SafeHanded does in HubSpot: internal notes on every step · close-to-purge · request from a ticket (deep link).

  • A HubSpot Super Admin (to create a service key or private app), and a SafeHanded Owner/Admin on the Team plan or above.
  • About ten minutes.

SafeHanded authenticates with a HubSpot Bearer access token — either credential type works:

  • Recommended — a Service Key: Development → Keys → Service keys → Create service key, with the scopes below. (HubSpot service keys)
  • Or a legacy Private App token: Settings → Integrations → Private Apps → Create a private app (creating new private apps in the UI is being disabled through late 2026; existing ones keep working).

Scopes: tickets (read and write tickets), crm.objects.contacts.read (requester name/email), crm.objects.companies.read (client mapping), crm.objects.owners.read (find the tickets assigned to you in the ticket picker).

Then in SafeHanded: Settings → Integrations → Connect → HubSpot Service Hub. Paste the token and (optionally, under Advanced & optional settings) your portal (hub) id so ticket links open in HubSpot, then click Connect and test.

Nothing to set up. SafeHanded polls HubSpot for status changes, so moving a ticket to a Closed stage purges its credential on the next poll. SafeHanded re-reads the ticket via the API before anything is purged — see how ticketing works.

HubSpot has no button that opens a web address with the ticket in it unless you build a UI extension (a developer app). The no-code route is a browser bookmark; SafeHanded’s ticket picker then finds the HubSpot ticket.

  1. In your browser, bookmark the link below, for example as New SafeHanded request.
  2. On a HubSpot ticket, click the bookmark, then search for the ticket in the New request window’s ticket picker and pick it.
https://safehanded.com/app/requests/new

Settings → Integrations → your HubSpot card → Activity shows this link ready to copy.

For a real one-click button on the ticket, a developer can build a HubSpot UI extension that opens this link, with TICKET_ID replaced by the ticket record ID (and then &preset= rather than ?preset= for a preset):

https://safehanded.com/app/requests/new?ticket=TICKET_ID

Choosing a preset (optional). A preset is a saved request — the reason, how long the credential is kept, who receives it and how the link is sent. To start from one, add ?preset= and the preset’s slug to the end of the link, for example ?preset=password-reset. Each preset’s slug is shown, with a copy button, under Settings → Request presets. With no preset in the link, SafeHanded uses the client’s default preset, then the organisation default (Settings → Policy → Default preset for new requests), and otherwise the policy defaults.

No click at all. Point a HubSpot workflow webhook (Operations Hub Pro) at a generic webhook integration’s trigger URL (Settings → Integrations → Generic webhook) with the SafeHanded trigger body; SafeHanded then creates the request with no one present. This needs a second ticketing integration (the generic webhook), which the MSP plan allows; the Team plan includes one ticketing integration. A request created this way is linked through the generic webhook integration, so its close-to-purge follows that integration’s setup, not HubSpot’s polling.

The status is the ticket’s pipeline stage. SafeHanded reads the pipeline definitions and maps by stage label — the default Support pipeline’s New → open, Waiting on us / Waiting on contact / On hold → pending, Closed → closed. Custom pipelines and stages show as unknown (never purge) until mapped.

  • Internal notes (associated to the ticket): created · submitted · (optionally) revealed · destroyed · expired · revoked · rotation recommended.
  • No public reply, and the chain-of-custody certificate isn’t attached to the HubSpot ticket — HubSpot notes are internal only; deliver the link by email or SMS, and get the certificate from the SafeHanded request page.
SymptomCause / fix
Test connection failsCheck the key has the tickets, crm.objects.contacts.read, crm.objects.companies.read, crm.objects.owners.read scopes and was copied whole. A 403 on a call means that scope is missing.
403 when posting a noteNote creation is authorised by the tickets write scope; if it still 403s, add crm.objects.contacts.write.
“Unknown status” on the cardMap the pipeline stage label in the status-map editor.