HubSpot retired its old static "API Keys" back in November 2022, so if you're looking for one today, you actually want one of two things: a Service Key (Settings → Integrations → Service Keys, in public beta since February 2026) for data-only, system-to-system access, or a private app access token (Settings → Integrations → Private Apps) if your integration needs webhooks. Both are sent the same way — as Authorization: Bearer <token>.
The rest of this page covers how to create each, where the credential goes, a working code sample, and the errors you'll hit if scopes or rate limits are off.
Prerequisites
- Super Admin access, or Developer Tools access in your HubSpot account's user permissions - required to create Service Keys or private apps (HubSpot Developers, Account Service Keys).
- A decision on whether your integration needs webhooks or UI extensions. If yes, you need a private app (or a project-based app via the HubSpot CLI) — Service Keys don't support webhooks. If you're only reading/writing CRM data on a schedule, a Service Key is the simpler, currently-recommended path (HubSpot Developer Blog, HubSpot Service Keys).
- A list of the CRM scopes your integration needs (e.g.,
crm.objects.contacts.read,crm.objects.deals.write) — both credential types follow least-privilege: you can only grant scopes you already have.
Step-by-step: creating a HubSpot Service Key (recommended for data integrations)
- In HubSpot, go to Settings → Integrations → Service Keys (some accounts surface this under Development → Keys → Service Keys in the left nav instead).
- Click Create a service key.
- Give it a descriptive name - something that identifies what it's for, like
powerbi-contacts-readornightly-deals-sync, not "my key." - Add the scopes the integration needs, reviewing each one against the principle of least privilege.
- Click Create, then immediately copy the key value - treat it like a password.
- Use the key as a Bearer token:
Authorization: Bearer <your-service-key>(HubSpot Developer Blog, HubSpot Service Keys).
If you need webhooks: use a private app instead
Service Keys don't support webhooks, UI extensions, or app pages. If your integration needs to react to HubSpot events in real time, create a private app: go to Settings → Integrations → Private Apps, click Create a private app, name it, select the scopes it needs under the Scopes tab, then open the Auth tab and click Show token to reveal the access token (HubSpot Developers, Private Apps overview). Private app tokens are also sent as Authorization: Bearer <token> and work the same way on API calls - the difference is in what each credential type can do, not how it authenticates.
Where the credential goes
Both Service Keys and private app access tokens go in the Authorization header as a bearer token:
Authorization: Bearer <your-token>against HubSpot's API base, e.g. https://api.hubapi.com/crm/v3/objects/contacts.
Connector-specific gotcha: Service Keys are account-level, data-only credentials - they explicitly do not support webhook subscriptions. If you build an integration on a Service Key and later need it to respond to HubSpot events (a deal stage change, a new contact, etc.), the key itself won't support that; you'll need to either add a private app / project-based app alongside it for the webhook piece, or rebuild the integration on a project-based app from the start (HubSpot Developer Changelog, Service Keys enter public beta).
A few other things to know:
- Lifetime: neither Service Keys nor private app tokens expire on their own. Service Keys can be rotated with a 7-day grace period during which both the old and new key work - useful for zero-downtime rotation.
- Scope: a key or token can only be granted scopes the creating user already holds, and is limited to exactly the scopes selected at creation. Add more later from the same settings page if your integration grows.
- Ownership: Service Keys are account-level - they keep working even if the person who created them leaves the account. Admins retain access to manage and rotate them.
- Revocation: rename, rotate, or delete a Service Key from Settings → Integrations → Service Keys; revoke a private app token by deleting the private app under Settings → Integrations → Private Apps.
If you're building for multiple HubSpot accounts (OAuth)
Service Keys and private apps are both single-account credentials. If you're distributing an integration that connects to other people's HubSpot accounts - a Marketplace app or a multi-tenant product - you need OAuth 2.0 via a project-based app built with the HubSpot CLI, not a Service Key or private app token (HubSpot Developer Blog, HubSpot Service Keys).
Minimal working example
This calls /crm/v3/objects/contacts with a limit of 1 — a good smoke test that confirms your token and scopes work.
curl:
curl "https://api.hubapi.com/crm/v3/objects/contacts?limit=1" \
-H "Authorization: Bearer $HUBSPOT_ACCESS_TOKEN"Node.js:
const res = await fetch(
"https://api.hubapi.com/crm/v3/objects/contacts?limit=1",
{
headers: {
Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`,
},
}
);
console.log(await res.json());Store HUBSPOT_ACCESS_TOKEN as an environment variable - never hard-code a Service Key or private app token in source control.
Common errors and fixes
Why am I getting 401 INVALID_AUTHENTICATION?
The token is missing, malformed, or has been deleted/rotated on HubSpot's side. Confirm the Authorization header is exactly Bearer <token> (with the space after "Bearer"), and that you're using the current key - if you recently rotated a Service Key, update every integration that referenced the old one before its grace period ends.
Why am I getting 403 with a scopes-related message?
Your Service Key or private app doesn't have the scope the endpoint requires (e.g., calling a deals endpoint without crm.objects.deals.read). Add the missing scope from Settings → Integrations → Service Keys (or the private app's Scopes tab), save, and re-copy the token if prompted.
Why am I getting 429 with errorType: "RATE_LIMIT"?
You've exceeded either a per-second or daily limit. The response body's policyName field says which (SECONDLY or DAILY), and response headers X-HubSpot-RateLimit-Remaining (burst, scoped to the window in X-HubSpot-RateLimit-Interval-Milliseconds) and X-HubSpot-RateLimit-Daily-Remaining show what's left. The older X-HubSpot-RateLimit-Secondly-Remaining header is still present but deprecated and no longer enforced (HubSpot Developers, API usage guidelines and limits).
The faster way
Choosing between Service Keys, private apps, and OAuth, then mapping scopes and watching per-second and daily limits works fine for one HubSpot account. It gets more involved once you're connecting HubSpot alongside other CRMs — each with its own auth model and object schema. Knit's unified CRM API handles HubSpot's auth and rate-limit backoff for you, and normalizes contacts, companies, and deals alongside connectors like Salesforce behind one schema. See the HubSpot API overview for what's available, or book a demo to see it against your own account. You can also sign up free and connect a sandbox HubSpot account.
FAQ
Does HubSpot still have "API keys"?
Not in the old sense - HubSpot retired its legacy static API keys (the ones passed as a hapikey query parameter) in November 2022. If you see a tutorial referencing ?hapikey=..., it no longer works. Today, "API key" searches usually mean a Service Key or a private app access token, both sent as Authorization: Bearer <token>.
What's the difference between a Service Key and a private app access token?
A Service Key is a newer (2026), account-level credential built specifically for data-only, system-to-system integrations - it's simple to create in Settings and supports clean rotation, but doesn't support webhooks. A private app access token is the older mechanism, also a Bearer token, but tied to a private app that can use webhooks and UI extensions. If you only need to read/write CRM data, HubSpot recommends Service Keys; if you need webhooks, use a private app or project-based app.
How do I authenticate to the HubSpot API?
Send your Service Key or private app access token as Authorization: Bearer <token> on every request to api.hubapi.com. There's no separate signing step or token exchange for either credential type - the token you copy from Settings is the token you use.
What scopes do I need for my HubSpot integration?
It depends on the objects you're working with - for example, crm.objects.contacts.read and .write for contacts, crm.objects.deals.read/.write for deals, and similar per-object scopes for companies and tickets. Both Service Keys and private apps let you select scopes individually at creation and add more later; grant only what your integration actually uses.
What happens if I exceed HubSpot's API rate limits?
HubSpot returns 429 with a JSON body containing errorType: "RATE_LIMIT" and a policyName of either SECONDLY (burst limit) or DAILY (daily cap). Response headers X-HubSpot-RateLimit-Remaining and X-HubSpot-RateLimit-Daily-Remaining let you check usage before hitting the limit (the older X-HubSpot-RateLimit-Secondly-Remaining header still appears but is deprecated). Knit handles this backoff automatically across the HubSpot connections it manages.

