Recipe: connect HubSpot
The HubSpot preset connects a board to your own HubSpot account through your own HubSpot app. Agents, column steps and people on a card can then look up contacts, companies and deals, and, if you allow it, create or change them and log notes and tasks on contacts. Read Connect a service that signs in with OAuth first: this page covers only what is different for HubSpot.
How it works:
- You pick the operations the connection may use. BakedBrie asks HubSpot for exactly the scopes those operations need, plus HubSpot's basic
oauthscope, and nothing more. Asking for a scope no chosen operation needs is refused. - A person signs in once in the browser. BakedBrie reads your HubSpot account ID (
hub_id) from HubSpot's token answer, so nobody types it. The connection then says which account it is signed in to. - Access tokens last 30 minutes. BakedBrie refreshes them by itself and keeps every token sealed.
- Writes run inside limits a person sets in the web app, are sent at most once, and are never retried by themselves.
- BakedBrie never sends email or messages from HubSpot. It refuses HubSpot's single-send email endpoints and its conversation and custom channel message endpoints, for every connection, whatever its scopes or labels. Notes and tasks carry no owner, so BakedBrie never assigns work to a person. HubSpot's own settings and automations may still notify people; those are outside BakedBrie.
Before you run it
HubSpot now makes new OAuth apps as developer-platform projects (creating legacy public apps ended June 23, 2026).
- Install the HubSpot CLI, version 7.6.0 or later, and run
hs account auth. - Run
hs project createand choose an app. - In the app's
app-hsmeta.json, set authtypetooauth,distributiontoprivate,redirectUrlsto this exact URL, andrequiredScopesto exactly the scopes BakedBrie shows for the operations you tick:
https://app.bakedbrie.com/settings/destinations/oauth/callback
- Run
hs project upload. Note the app's client id. Put its client secret in an environment variable in your own shell, for exampleexport HUBSPOT_CLIENT_SECRET=.... Never paste it into the chat. - Only a Super Admin of the HubSpot account can install the app. A private app installs into at most 10 HubSpot accounts (100 when it was made in a Solutions Partner account).
whoamimust showconnectionsandconnections_oauthon.
Operations and scopes
| Operation | What it does | Reads or writes | Scopes |
|---|---|---|---|
contacts_search | Contacts whose email is exactly an address, up to 10 | reads | crm.objects.contacts.read |
contact_get | One contact: name, email, lifecycle stage | reads | crm.objects.contacts.read |
companies_search | Companies whose domain is exactly a host name, up to 10 | reads | crm.objects.companies.read |
company_get | One company: name, domain, lifecycle stage | reads | crm.objects.companies.read |
deals_search | Deals in one stage, up to 25 | reads | crm.objects.deals.read |
deal_get | One deal: name, amount, stage, pipeline, close date | reads | crm.objects.deals.read |
contact_create | Creates a contact with an email and a name | writes | crm.objects.contacts.write |
contact_update | Sets a contact's lifecycle stage | writes | crm.objects.contacts.write |
company_create | Creates a company with a name and a domain | writes | crm.objects.companies.write |
company_update | Sets a company's lifecycle stage | writes | crm.objects.companies.write |
deal_create | Creates a deal in a pipeline and stage with an amount | writes | crm.objects.deals.write |
deal_update | Sets a deal's stage and amount | writes | crm.objects.deals.write |
note_create | Logs a note on a contact | writes | crm.objects.contacts.read, crm.objects.contacts.write |
task_create | Creates a task on a contact, not started and assigned to nobody | writes | crm.objects.contacts.read, crm.objects.contacts.write |
The six reads are ticked when the create form opens; writes never are. Stages, pipelines and lifecycle stages are HubSpot's internal values (such as appointmentscheduled), not the labels you see in HubSpot. Updates change only the named properties; to change others, edit the connection's JSON.
A contact's email from contacts_search or contact_get read on a card may address a Gmail or Outlook draft of that card. No other HubSpot field can.
The prompt
In BakedBrie, connect HubSpot to the board "{{BOARD_NAME}}" with the HubSpot preset. Use only the BakedBrie MCP tools. Start with whoami and stop if connections or connections_oauth is off. First read /docs/recipes/connections-oauth and /docs/recipes/hubspot with read_docs.
My HubSpot app's client id is {{CLIENT_ID}}. The client secret is in my environment variable {{ENV_VAR}}.
Operations to allow: {{OPERATIONS, for example contacts_search, contact_get, note_create}}.
1. Call manage_connection with action presets and show me the HubSpot operations and the scopes they need.
2. Create the connection with manage_connection create: preset hubspot, the operations above, my client id. Give the client secret with prepare_secret, never in the chat.
3. Tell me the exact scopes to put in requiredScopes in app-hsmeta.json.
4. Call connect_oauth and give me the sign-in link. Only a person can finish signing in.
5. Attach the connection to the board with a short handle, such as crm, and the operations above.
6. Stop and tell me what a person must do in the web app: finish signing in, then set limits for each operation.
Limits, taint and triggers
- HubSpot does not charge per call. Your HubSpot plan allows 100 calls per 10 seconds on Free and Starter, 190 on Professional and Enterprise, and search allows 5 calls a second. When HubSpot answers busy, it has not accepted the call, so BakedBrie waits and tries again, up to three times.
- Contact, company and deal names, notes and task text are free text. When a read on a card brings free text back, that card accepts only reads for the rest of that round of work, so text inside HubSpot can never steer a write.
- HubSpot documents no idempotency key. BakedBrie still sends each write at most once. If it cannot tell whether HubSpot accepted a write, it says so and never sends it again by itself: check HubSpot for the change before you send it again.
- CRM changes can start work through a customer-owned HubSpot webhook subscription once its signed events are verified in BakedBrie. Register the notification URL from Board → Automate → When a service changes in your HubSpot app, then check the source state. A scheduled read remains available when provider-side subscription setup is unavailable.
- Disconnecting revokes the refresh token at HubSpot. HubSpot documents no way to revoke an access token; the last one stops working within 30 minutes.
- The sign-in uses HubSpot's date-versioned token endpoint. HubSpot's older v1 OAuth endpoints stop working on February 16, 2027; BakedBrie does not use them.