Connect a custom AI agent to HubSpot through a small backend, never directly. Use a private app for your own HubSpot account or OAuth when customers connect theirs, with minimum scopes and the token stored server-side. Give the agent narrow tools that read an allowlist of properties and propose changes to one dedicated output property. Validate the output, approve each write, read the record back, and log every operation so retries never duplicate. Add webhook triggers last, verifying HubSpot's signature and excluding the agent's own output field so it cannot trigger itself.
What does connecting a custom AI agent to HubSpot involve?
A custom AI agent never talks to HubSpot directly. It talks to a small backend you own, and that backend talks to HubSpot. The backend holds the HubSpot credential, decides which records and fields the agent can read, checks everything the agent wants to write, and only then calls HubSpot's CRM API.
That split is the whole design. The model is good at reading a contact, a deal history and a call note and proposing a summary, a next step or a lead score. It is not a permission system. Give it a raw API token and a general-purpose HTTP tool and one badly-worded note on a contact record is enough to have it update fields nobody asked it to touch - the risk we cover in prompt injection in AI agents.
The worked example below is deliberately narrow: read a contact, have the agent write an account summary, get it approved, and save it to one dedicated contact property. Once that works end to end, adding deals, tickets or more actions is the same pattern again.
Should you use a private app or OAuth to connect an agent to HubSpot?
It depends on whose HubSpot account the agent works in.
| Option | Use it when | What you manage |
|---|---|---|
| Private app (static access token) | The agent works in your own single HubSpot account | One token with chosen scopes, stored as a secret and rotated |
| OAuth app | Customers connect their own HubSpot accounts to your product | An install flow, a token per account, refresh, and uninstall handling |
HubSpot has been reworking its developer platform and renaming app types, so check its current developer docs for what each is called in your account. The decision itself is stable: one account, one static token; many customer accounts, OAuth.
Either way, ask only for the scopes the first workflow needs. Reading and updating contacts takes crm.objects.contacts.read and crm.objects.contacts.write. Add deals, tickets or notes later, when a workflow actually needs them.
Which HubSpot fields should the agent be allowed to read and write?
Write this down before any code. It is the contract the backend enforces.
- Read allowlist: the handful of contact properties the task needs - job title, company, lifecycle stage, last activity date. Not every property on the record.
- One output property: create a dedicated multi-line text property, such as "Agent account summary", under Settings, Properties, on the contact object. The agent writes only there.
- Internal names, not labels: the API uses a property's internal name, which often differs from the label in the HubSpot UI. Record both, and keep the mapping in backend config.
- Rejection rules: an unknown record ID, any field outside the allowlist, or a summary that adds facts not in the input is rejected, not written.
Starting with a new property rather than overwriting an existing one means a bad write damages nothing your sales team relies on, and you can compare the agent's output with what people already wrote.
How do you connect a custom AI agent to HubSpot, step by step?
- 01
Create the app and store the token server-side
Set the minimum scopes, then put the token in your deployment's secret store. It never goes into a prompt, browser code, source control or logs.
- 02
Prove a read and a write with no AI involved
From the backend, fetch one test contact through the CRM contacts API, requesting only the allowlisted properties. Then update the output property on that contact and check the value in HubSpot.
- 03
Give the agent narrow tools, not the API
Expose two functions: get_contact(id), which returns only allowlisted fields, and propose_summary(id, text), which records a proposal. Neither accepts a field name, URL or token from the model.
- 04
Validate the agent's output
Require structured output - record ID and summary text - and check the ID matches the contact you sent, the text is within length limits, and nothing in it is a field name or instruction.
- 05
Approve, write, then read back
A reviewer sees the input fields and the proposed summary side by side. On approval the backend writes the property, fetches the contact again, and confirms the saved value matches.
- 06
Log every operation with an ID
Store the record, an input fingerprint, the proposal, the approval and the result together. A retry checks this log first, so a timeout never turns into a duplicate write.
Keep the approval step until the agent has a track record on real contacts. Removing it is a decision you make with evidence - see our AI agent go-live checklist for what that evidence looks like.
How do you run the agent automatically when a HubSpot record changes?
Start with a manual button or command while you test. Once the write path is solid, there are three ways to trigger it automatically:
| Trigger | How it works | Watch out for |
|---|---|---|
| Webhook subscription | HubSpot calls your endpoint when a subscribed property changes | Verify the request signature, queue the event, deduplicate by event ID |
| HubSpot workflow action | A HubSpot workflow sends a webhook to your backend when its criteria match | Available on some HubSpot tiers only; criteria live in HubSpot, not your code |
| Scheduled polling | Your backend searches for recently modified records on a timer | Store a checkpoint, handle pagination, and stay inside rate limits |
Two rules apply to all three. Verify webhook requests using HubSpot's signature header before trusting them, then fetch the current record from HubSpot rather than acting on the event payload. And never trigger on the property the agent writes - otherwise saving a summary fires another summary job, forever.
Can you use HubSpot's MCP server instead of building a backend?
HubSpot offers a Model Context Protocol (MCP) server that lets AI assistants read and update CRM data directly. It is a quick way for a person to query HubSpot from an AI chat. For an agent that writes to records unattended, it does not replace the backend above: you still need the field allowlist, output checks, approval and the operation log, and you will want them in code you control. Our MCP explainer covers where MCP fits and where it does not.
What usually goes wrong with a HubSpot AI agent integration?
The write succeeds but the field stays empty
The request used the property's label instead of its internal name, or targeted the wrong object. Check the internal name in the property settings and keep that mapping in config, never in the prompt.
Requests start failing with HTTP 429
HubSpot limits requests per ten-second window and per day, and the limits depend on your plan and app type. Queue work, back off using the response headers, and batch reads where the API allows it rather than retrying everything at once.
The same contact keeps getting processed
The trigger includes the agent's own output property, or events are not deduplicated. Remove the output field from the trigger and skip jobs whose input fingerprint has not changed since the last approved run.
The summary repeats instructions from a note
Free-text fields such as notes and emails are untrusted input. Mark them as data in the prompt, keep the agent's tools narrow, and let validation reject output that does not match the expected shape.
How do you connect a custom AI agent to HubSpot safely?
Put a backend between the agent and HubSpot. Use a private app for your own account or OAuth for customers' accounts, with the minimum scopes and the token kept server-side. Let the agent read an allowlist of properties and write to one dedicated property through narrow tools, validate its output, approve each write, read it back, and log every operation so retries never duplicate. Add webhook triggers last, with signature checks and the output field excluded.
The final acceptance test is a blocked write: ask the agent to update a field outside the allowlist and confirm the backend refuses. If you want the integration built, our AI integration team connects agents to HubSpot and other CRMs, and our guide to AI integration services explains what that work involves.
