A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The HubSpot API is how an app or AI agent works with a HubSpot account: reading and creating contacts, updating a deal's stage, opening a support ticket, or linking a contact to a company. Access is granted through a Bearer token, either a private app token tied to one account or an OAuth token for a public app, and the token's scopes, like crm.objects.contacts.read or crm.objects.deals.write, decide which objects a call can read or write. A state change can be pushed to a public app as a webhook event.
How an app or AI agent connects to HubSpot determines what it can reach. There is a REST route for making calls, a webhook route for receiving events, and a hosted server that exposes HubSpot tools to agents, and each is governed by the token behind it and the scopes that token carries.
The REST API answers at https://api.hubapi.com, takes and returns JSON, and pages through lists with a cursor. A call authenticates with a Bearer token, either a private app access token or an OAuth access token, and the token's scopes decide what it can reach. CRM objects sit at /crm/v3/objects, associations at /crm/v4, and properties at /crm/v3/properties.
A public app subscribes to event types through the Webhooks v3 API at webhooks/v3/{appId}/subscriptions and registers an HTTPS URL. HubSpot then POSTs events, like contact.creation or deal.propertyChange, to that URL. Each delivery carries an X-HubSpot-Signature header, a SHA-256 hash of the app secret and the request body, so the receiver can confirm it came from HubSpot.
A hosted Model Context Protocol server at https://mcp.hubspot.com exposes HubSpot tools to AI agents and LLM clients. It went generally available on 13 April 2026. It authenticates with OAuth using PKCE, and an app's read and write scopes set what the agent can do. Tools cover reading, creating, updating, and searching CRM records like contacts, companies, deals, and tickets, plus property and owner lookups, with search built on the CRM Search API.
A private app belongs to one HubSpot account and is granted a fixed set of scopes. It produces a static access token that does not expire, sent as a Bearer token. This is the recommended way to connect a single account, and the token must be kept server-side.
A public app, installable across many accounts, uses the OAuth 2.0 authorization-code flow. The installing user approves the app's requested scopes, and the app exchanges the code for an access token and a refresh token. The access token is short-lived, typically about 30 minutes, and is refreshed with the refresh token.
The HubSpot API is split into the CRM objects an agent can act on, like contacts, companies, deals, and tickets, plus the associations that link them and the properties that define their fields. Each object has its own read and write scope, and a write changes real CRM records.
List, read, create, update, archive, and search contact records, and act on them in batches.
List, read, create, update, and search company records.
List, read, create, update, and search deal records in the sales pipeline.
List, read, create, update, and search support ticket records.
Link and unlink records across objects, like a contact to a company or a deal, and read those links.
Read the fields defined on an object and create new ones.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
ContactsList, read, create, update, archive, and search contact records, and act on them in batches.8 | ||||||
| GET | /crm/v3/objects/contacts | Retrieve a page of contacts. | read | crm.objects.contacts.read | Current | |
Read-only. Acts oncontact Permission (capability) crm.objects.contacts.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /crm/v3/objects/contacts/{contactId} | Retrieve a single contact by id. | read | crm.objects.contacts.read | Current | |
Read-only. Sensitive fields need crm.objects.contacts.sensitive.read on top. Acts oncontact Permission (capability) crm.objects.contacts.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/contacts | Create a contact. | write | crm.objects.contacts.write | Current | |
A core write. Acts oncontact Permission (capability) crm.objects.contacts.writeVersionAvailable since the API’s base version Webhook event contact.creationRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /crm/v3/objects/contacts/{contactId} | Update a contact's properties. | write | crm.objects.contacts.write | Current | |
A core write. Acts oncontact Permission (capability) crm.objects.contacts.writeVersionAvailable since the API’s base version Webhook event contact.propertyChangeRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /crm/v3/objects/contacts/{contactId} | Archive a contact, moving it to the recycling bin. | write | crm.objects.contacts.write | Current | |
Archives rather than permanently deletes; a separate GDPR-delete endpoint erases for good. Acts oncontact Permission (capability) crm.objects.contacts.writeVersionAvailable since the API’s base version Webhook event contact.deletionRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/contacts/search | Search and filter contacts with filter groups, sorting, and pagination. | read | crm.objects.contacts.read | Current | |
Read-only. The CRM Search API has its own limit of 4 requests per second per token, separate from the burst limit. Acts oncontact Permission (capability) crm.objects.contacts.readVersionAvailable since the API’s base version Webhook eventNone Rate limit4 requests/sec (CRM Search) SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/contacts/batch/create | Create up to 100 contacts in one request. | write | crm.objects.contacts.write | Current | |
A batch request counts as a single call against the rate limit but acts on many records. Acts oncontact Permission (capability) crm.objects.contacts.writeVersionAvailable since the API’s base version Webhook event contact.creationRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/contacts/batch/read | Retrieve up to 100 contacts by id or a unique property. | read | crm.objects.contacts.read | Current | |
Read-only. Acts oncontact Permission (capability) crm.objects.contacts.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
CompaniesList, read, create, update, and search company records.4 | ||||||
| GET | /crm/v3/objects/companies | Retrieve a page of companies. | read | crm.objects.companies.read | Current | |
Read-only. Acts oncompany Permission (capability) crm.objects.companies.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/companies | Create a company. | write | crm.objects.companies.write | Current | |
A core write. Acts oncompany Permission (capability) crm.objects.companies.writeVersionAvailable since the API’s base version Webhook event company.creationRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /crm/v3/objects/companies/{companyId} | Update a company's properties. | write | crm.objects.companies.write | Current | |
A core write. Acts oncompany Permission (capability) crm.objects.companies.writeVersionAvailable since the API’s base version Webhook event company.propertyChangeRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/companies/search | Search and filter companies with filter groups, sorting, and pagination. | read | crm.objects.companies.read | Current | |
Read-only. Subject to the CRM Search API limit of 4 requests per second per token. Acts oncompany Permission (capability) crm.objects.companies.readVersionAvailable since the API’s base version Webhook eventNone Rate limit4 requests/sec (CRM Search) SourceOfficial documentation ↗ | ||||||
DealsList, read, create, update, and search deal records in the sales pipeline.4 | ||||||
| GET | /crm/v3/objects/deals | Retrieve a page of deals. | read | crm.objects.deals.read | Current | |
Read-only. Acts ondeal Permission (capability) crm.objects.deals.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/deals | Create a deal. | write | crm.objects.deals.write | Current | |
A core write. Acts ondeal Permission (capability) crm.objects.deals.writeVersionAvailable since the API’s base version Webhook event deal.creationRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /crm/v3/objects/deals/{dealId} | Update a deal's properties, like its stage or amount. | write | crm.objects.deals.write | Current | |
A core write; moving a deal stage fires deal.propertyChange. Acts ondeal Permission (capability) crm.objects.deals.writeVersionAvailable since the API’s base version Webhook event deal.propertyChangeRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/deals/search | Search and filter deals with filter groups, sorting, and pagination. | read | crm.objects.deals.read | Current | |
Read-only. Subject to the CRM Search API limit of 4 requests per second per token. Acts ondeal Permission (capability) crm.objects.deals.readVersionAvailable since the API’s base version Webhook eventNone Rate limit4 requests/sec (CRM Search) SourceOfficial documentation ↗ | ||||||
TicketsList, read, create, update, and search support ticket records.4 | ||||||
| GET | /crm/v3/objects/tickets | Retrieve a page of support tickets. | read | crm.objects.tickets.read | Current | |
Read-only. The tickets spec also accepts the legacy tickets scope, which covers both read and write. Acts onticket Permission (capability) crm.objects.tickets.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/tickets | Create a support ticket. | write | crm.objects.tickets.write | Current | |
A core write. The legacy tickets scope also grants this. Acts onticket Permission (capability) crm.objects.tickets.writeVersionAvailable since the API’s base version Webhook event ticket.creationRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /crm/v3/objects/tickets/{ticketId} | Update a ticket's properties, like its pipeline stage or priority. | write | crm.objects.tickets.write | Current | |
A core write. The legacy tickets scope also grants this. Acts onticket Permission (capability) crm.objects.tickets.writeVersionAvailable since the API’s base version Webhook event ticket.propertyChangeRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/objects/tickets/search | Search and filter tickets with filter groups, sorting, and pagination. | read | crm.objects.tickets.read | Current | |
Read-only. Subject to the CRM Search API limit of 4 requests per second per token. Acts onticket Permission (capability) crm.objects.tickets.readVersionAvailable since the API’s base version Webhook eventNone Rate limit4 requests/sec (CRM Search) SourceOfficial documentation ↗ | ||||||
AssociationsLink and unlink records across objects, like a contact to a company or a deal, and read those links.4 | ||||||
| PUT | /crm/v4/objects/{fromObjectType}/{fromObjectId}/associations/default/{toObjectType}/{toObjectId} | Link two records using the default association type, like a contact to a company. | write | crm.objects.contacts.write | Current | |
Needs write on both objects being linked, so the exact scopes vary by object type; this is the v4 Associations API. Acts onassociation Permission (capability) crm.objects.contacts.writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /crm/v4/objects/{objectType}/{objectId}/associations/{toObjectType}/{toObjectId} | Link two records with a specific association label. | write | crm.objects.contacts.write | Current | |
Needs write on both linked objects; the scope set varies by object type. Acts onassociation Permission (capability) crm.objects.contacts.writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /crm/v4/objects/{objectType}/{objectId}/associations/{toObjectType} | Read all of a record's associations to a given object type. | read | crm.objects.contacts.read | Current | |
Read-only. Needs read on both objects; the scope set varies by object type. Acts onassociation Permission (capability) crm.objects.contacts.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /crm/v4/objects/{objectType}/{objectId}/associations/{toObjectType}/{toObjectId} | Remove all association labels between two records. | write | crm.objects.contacts.write | Current | |
Unlinks the records without deleting either; needs write on both objects. Acts onassociation Permission (capability) crm.objects.contacts.writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
PropertiesRead the fields defined on an object and create new ones.3 | ||||||
| GET | /crm/v3/properties/{objectType} | Read all properties defined for an object type. | read | crm.schemas.contacts.read | Current | |
Read-only. The schema scope matches the object, like crm.schemas.deals.read; the object's own read scope also grants it. Acts onproperty Permission (capability) crm.schemas.contacts.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /crm/v3/properties/{objectType}/{propertyName} | Read a single property's definition by name. | read | crm.schemas.contacts.read | Current | |
Read-only. The schema scope matches the object type in the path. Acts onproperty Permission (capability) crm.schemas.contacts.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /crm/v3/properties/{objectType} | Create a new property (field) on an object type. | write | crm.schemas.contacts.write | Current | |
Changes the account's field definitions for every record of that object; the schema write scope matches the object. Acts onproperty Permission (capability) crm.schemas.contacts.writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
HubSpot can notify an app when something happens in an account, like a contact being created or a deal property changing. A public app subscribes to event types, and HubSpot posts the events to a registered URL, so an integration learns about activity without polling.
| Event | What it signals | Triggered by |
|---|---|---|
contact.creation | A new contact was created in the account. | /crm/v3/objects/contacts/crm/v3/objects/contacts/batch/create |
contact.propertyChange | A property on a contact changed. The subscription names the property to watch. | /crm/v3/objects/contacts/{contactId} |
contact.deletion | A contact was deleted or archived. | /crm/v3/objects/contacts/{contactId} |
company.creation | A new company was created in the account. | /crm/v3/objects/companies |
company.propertyChange | A property on a company changed. | /crm/v3/objects/companies/{companyId} |
deal.creation | A new deal was created in the account. | /crm/v3/objects/deals |
deal.propertyChange | A property on a deal changed, like its stage or amount. | /crm/v3/objects/deals/{dealId} |
ticket.creation | A new support ticket was created in the account. | /crm/v3/objects/tickets |
ticket.propertyChange | A property on a ticket changed, like its pipeline stage or priority. | /crm/v3/objects/tickets/{ticketId} |
HubSpot limits how fast and how much an app can call, by a burst rate measured over ten seconds and by a separate daily request quota, both depending on the account's subscription and any limit-increase add-on.
HubSpot meters requests two ways, both depending on the account's subscription and any API Limit Increase add-on. The first is a burst limit per private app, measured over ten seconds: 100 per ten seconds on Free and Starter, 190 per ten seconds on Professional and Enterprise, and 250 per ten seconds with the add-on. The second is a daily quota shared across all of an account's private apps: 250,000 requests a day on Free and Starter, 625,000 on Professional, and 1,000,000 on Enterprise, with the add-on lifting the daily ceiling to 1,000,000. A publicly distributed OAuth app is instead capped at 110 requests per ten seconds per account that installs it. The CRM Search API has its own separate limit of 4 requests per second per token. Going over any of these returns HTTP 429, with the X-HubSpot-RateLimit-Daily, X-HubSpot-RateLimit-Daily-Remaining, X-HubSpot-RateLimit-Max, and X-HubSpot-RateLimit-Remaining headers reporting the current state and a Retry-After header on the response.
CRM list endpoints are cursor-based: a limit parameter sets the page size and the response returns paging.next.after, an opaque cursor passed as after to fetch the following page. A search request pages the same way and also caps how deep it goes. Batch read endpoints take up to 100 ids per request instead of paging.
A batch endpoint acts on at most 100 records per request. A search request returns at most 200 records per page and a maximum of 10,000 total results per query, and allows up to five filter groups with up to six filters each. A single property value is capped at 65,536 characters.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | VALIDATION_ERROR | The request was bad: a required field is missing, a value is the wrong type, or a value fails validation. The response body holds an errors array with a code and context per field. | Read the message and the errors array, fix the named fields, and resend. The request is not retryable as-is. |
| 401 | Unauthorized | Authentication is missing or invalid: no Bearer token, a malformed Authorization header, or an expired OAuth token. | Send a valid private app or OAuth access token in the Authorization header, refreshing an expired OAuth token first. |
| 403 | Forbidden | The token is valid but lacks the scope the request needs, or the account does not have access to the feature. | Grant the missing scope to the app, then reauthorize, or confirm the account's subscription covers the endpoint. |
| 404 | Not Found | The requested record or endpoint does not exist, for example a bad object id or a deleted record. | Verify the id and the path, and confirm the record was not archived. |
| 429 | RATE_LIMIT | A rate limit was hit: the per-app ten-second burst limit, the account's daily quota, or the CRM Search API's per-second limit. The X-HubSpot-RateLimit-* headers report the current state. | Back off using the Retry-After header, then retry with exponential backoff, and smooth the request rate. |
| 502 | Bad Gateway / Service Unavailable | A transient error on HubSpot's side, which can also appear as 503 or 504. | Retry with exponential backoff, and contact HubSpot support if it persists. |
HubSpot versions its CRM endpoints in the path, with the stable objects, associations, and properties APIs at v3 and v4, and ships dated changes through its developer changelog rather than a single pinned account version.
HubSpot versions its CRM endpoints in the path. The core objects, search, properties, and owners APIs are at v3, while the associations API is at v4. HubSpot does not pin one dated API version per account; instead a fixed path version stays stable and changes are announced through the developer changelog.
The hosted Model Context Protocol server at mcp.hubspot.com graduated from public beta to general availability, giving AI agents an OAuth-authenticated, scope-governed way to read, write, and search CRM data.
HubSpot raised the CRM Search API limit from one request per second to four requests per second per authentication token, the separate per-second cap that still governs all search endpoints today.
An integration calls a fixed path version and moves up when HubSpot ships a new one.
HubSpot developer changelog ↗Bollard AI sits between a team's AI agents and HubSpot. Grant each agent exactly the access it needs, read or write, object by object, and every call is checked and logged.