GoHighLevel supports two main authorization models for modern API integrations: Private Integration Tokens (PITs) and OAuth 2.0.
Both can provide scoped access to the HighLevel API, but they solve different integration problems.
A Private Integration Token is usually the simpler choice when the integration is internal, controlled by your own team, and only needs direct server-to-server access to a specific HighLevel account or location.
OAuth 2.0 becomes the better choice when customers need to connect their own HighLevel accounts, when an application is installed across multiple agencies or sub-accounts, or when you need a proper installation and authorization lifecycle.
A useful starting point is:
Situation
Better Starting Point
Internal script for your own HighLevel account
Private Integration Token
Private backend integration for one client/location
Private Integration Token
Internal reporting or synchronization
Private Integration Token
App installed by many HighLevel customers
OAuth
Marketplace-style integration
OAuth
Users authorize their own HighLevel account
OAuth
Installation across many independent sub-accounts
OAuth
App needs an installation lifecycle
OAuth
The decision is not about which authentication model is more advanced.
It is about who owns the integration, who authorizes it, how many accounts it needs to serve, and how credentials must be managed over time.
What Is a GoHighLevel Private Integration Token?
A Private Integration Token, commonly called a PIT, is a scoped credential generated directly inside HighLevel.
It can be sent as a Bearer token when calling supported HighLevel APIs.
The architecture is simple:
Your backend
↓
Private Integration Token
↓
HighLevel APIUnlike OAuth, a PIT does not require a customer-facing authorization flow.
You create the Private Integration, select the permissions it needs, generate the token, store it securely, and use it from your application.
Conceptually:
Generated manually
↓
Scoped permissions
↓
Static credential
↓
No OAuth consent flow
↓
No access-token refresh flowThat simplicity is exactly why PITs can be useful for internal integrations.
When a Private Integration Token Makes Sense
A PIT can be a strong fit for:
- internal data synchronization;
- private reporting tools;
- a backend used by your own business;
- one controlled client integration;
- scheduled internal jobs;
- server-to-server API access;
- development or testing where an installation flow is unnecessary.
For example:
Internal reporting service
↓
PIT
↓
HighLevel Location
↓
Read CRM dataIf one company owns both the application and the HighLevel environment, there may be little value in building OAuth authorization, callbacks, refresh-token storage, and installation management.
In that case, OAuth would add infrastructure without solving an actual business problem.
For this system I used Private Integration Tokens rather than OAuth. The integration is a backend I control that drives outbound calls and SMS sequences through the HighLevel API on behalf of the accounts it serves. There is no external customer who installs the app and authorizes it themselves; the integration and the HighLevel environments are managed together, so a PIT per location gives the backend the direct server-to-server access it needs.
OAuth would have added an authorization flow, redirect handling, token exchange, refresh-token storage, and installation records, none of which solve a problem this integration has. Nobody needs to click "connect my HighLevel account," so the entire OAuth installation lifecycle would be infrastructure without a purpose. The honest tradeoff is that PIT does not onboard many independent third-party customers cleanly, since each location's token is provisioned rather than self-authorized. That is a real limit of the approach, but for a controlled integration where the same team manages the accounts and the backend, the scoped PIT is the simpler credential and OAuth's lifecycle would be complexity without benefit.
What Is GoHighLevel OAuth 2.0?
OAuth solves a different problem.
Instead of an administrator manually generating a token and giving it to the application, a HighLevel user authorizes the application through an installation flow.
Conceptually:
HighLevel user
↓
Install / Authorize App
↓
Authorization Code
↓
Your application
↓
Exchange code for tokens
↓
Access Token + Refresh Token
↓
HighLevel APIThe application defines the permissions it needs, redirects the user through authorization, receives an authorization code, and exchanges that code for tokens.
The important difference is ownership.
With a PIT:
Developer/admin creates credential
→ integration uses credentialWith OAuth:
User installs app
→ user grants access
→ app receives authorization
→ app manages that installationOAuth is therefore much better suited to software that other HighLevel users need to connect themselves.
When OAuth Makes Sense
OAuth is the natural fit when:
- you are building an installable integration;
- multiple customers need to connect their own HighLevel accounts;
- each installation belongs to a different agency or location;
- the application has a Marketplace-style distribution model;
- users need to grant and revoke access themselves;
- you need a standardized installation lifecycle;
- app-level features depend on an authorized installation.
For example:
Client A ──authorize──┐
│
Client B ──authorize──┼→ Your application
│ ↓
Client C ──authorize──┘ tenant-specific tokens
↓
HighLevel APIThat is fundamentally different from storing one manually generated token in server configuration.
Private Integration vs OAuth: The Main Differences
Private Integration Token
OAuth 2.0
Credential creation
Generated manually in HighLevel
Generated through OAuth authorization
Customer consent flow
No
Yes
Access model
Static credential
Access + refresh token lifecycle
Best fit
Internal/controlled integrations
Installable/multi-customer applications
Scopes
Yes
Yes
Manual setup
Yes
Automated after OAuth flow is built
Multi-client authorization
Difficult to manage manually
Natural fit
Marketplace/app lifecycle
Limited fit
Designed for it
Token refresh logic
Not required
Required
Credential rotation
Operational/manual
OAuth lifecycle
Internal server-to-server use
Strong fit
Often unnecessary complexity
A useful question is:
Who is expected to authorize this integration?
If the answer is:
“Our own team for our own HighLevel environment.”
a PIT may be enough.
If the answer is:
“Every agency or customer that connects our product.”
OAuth is usually the better architecture.
Private Integration Is Not the Same as a Private OAuth App
The terminology can be confusing.
A Private Integration Token and a private OAuth application are not the same thing.
A private OAuth app still uses OAuth:
Private OAuth App
↓
OAuth authorization flow
↓
Access + refresh tokensA Private Integration uses a PIT:
Private Integration
↓
Generate PIT
↓
Static Bearer credentialSo there are two separate decisions:
How is API access authorized?
→ PIT or OAuth
How is an OAuth app distributed?
→ Private or PublicDo not confuse those two concepts.
Private Integration Tokens Are Not the Old HighLevel API Keys
Another common source of confusion is older HighLevel API tutorials.
A modern Private Integration Token is not simply a renamed legacy API key.
The safer mental model is:
Private Integration Token
→ modern scoped API authorization
Legacy API key
→ older authentication modelThis matters because older examples may use authentication patterns, endpoints, or assumptions that should not be copied into a new production integration.
For a new HighLevel integration, start with the current authorization model rather than treating old API-key tutorials as the source of truth.
Authentication is only one part of the system. For the complete production pattern, see GoHighLevel API integration architecture
Scopes Matter With Both PIT and OAuth
Choosing a PIT does not mean giving the application unrestricted API access.
Both PIT and OAuth integrations should use only the permissions required by the application.
A safer design starts with the integration requirement:
Business requirement
↓
Required API operations
↓
Minimum required scopes
↓
CredentialFor example, if an internal reporting tool only needs to read contacts, there is no reason to give it unrelated write permissions.
This reduces the impact of:
- credential compromise;
- programming mistakes;
- accidental writes;
- future code changes.
Scopes are part of the security architecture.
Missing Scope vs Invalid Credential
When an API request fails, distinguish between:
The token is invalidand:
The token is valid
but does not have the required permissionThose are different failures.
Refreshing or replacing a valid credential will not fix a missing scope.
The application needs the correct authorization scope for the operation it is attempting.
A HighLevel API call started returning a permission error when I added a new operation the integration hadn't used before. The failure looked like an auth error, but the credential was valid and working for every other call, which was the tell: this wasn't an expired or wrong token, it was a missing scope. A credential that authenticates fine for reads but fails on one specific operation points at permissions, not identity.
I identified it by separating the two failure types the API can return: an invalid credential fails everywhere, while a missing scope fails only on the operation that needs it. Since the token worked elsewhere, refreshing or replacing it would have fixed nothing. The fix was in the Private Integration settings: the scope for that operation hadn't been enabled, so I added it and re-saved, and the call succeeded. No credential value was ever exposed in the process, since the scope is configured in HighLevel's interface, not in the token itself.
OAuth Requires a Token Lifecycle
One of the biggest differences between PIT and OAuth appears after installation.
A PIT is a static credential until it is rotated or revoked.
OAuth access tokens expire.
That means OAuth requires an ongoing token-management process.
Conceptually:
OAuth installation
↓
Access Token
Refresh Token
↓
API requests
↓
Access Token expires
↓
Refresh
↓
New Access Token
New Refresh Token
↓
Persist bothThat final step is important.
When HighLevel returns a new access token and refresh token, the application should persist the new credential state.
Do not design the integration around:
refresh
↓
save new access token
↓
keep using old refresh token foreverThe authentication store should treat the refreshed credentials as a new token pair.
A useful state transition is:
Current:
accessToken A
refreshToken A
↓ refresh
New:
accessToken B
refreshToken B
↓
Persist B + BToken management is therefore part of the application architecture, not just an API request detail.
Do Not Refresh Every Time You Receive a 401
Another common mistake is treating every:
401 Unauthorizedas proof that the OAuth access token expired.
A 401 can also come from:
- an invalid credential;
- revoked authorization;
- an incorrect Authorization header;
- using the wrong token context;
- another authentication problem.
So avoid this logic:
any 401
→ refresh tokenA better model is:
401
↓
inspect authentication failure
↓
token expired?
├── Yes → refresh → persist new token pair → retry
└── No → investigate actual authentication problemOtherwise an application can repeatedly refresh tokens while hiding the real configuration problem.
Private Integration Tokens Have a Different Lifecycle
PITs avoid the OAuth access-token refresh process.
But a static credential still needs operational management.
A safe rotation process looks like this:
PIT A in production
↓
Generate replacement credential
↓
Update application
↓
Verify production traffic
↓
Retire PIT AThe important point is:
Static does not mean permanent.
A PIT should still have procedures for:
- secure storage;
- rotation;
- revocation;
- credential compromise;
- deployment updates.
If a token becomes exposed, it should be replaced rather than treated as permanent infrastructure.
Rotating a PIT without downtime relies on the old and new tokens being valid at the same time. The procedure is to generate a replacement Private Integration in HighLevel while the existing one is still active, deploy the new token to the credential store, confirm live traffic is authenticating on it, and only then revoke the old token. Because both credentials work during the overlap, there is no moment where in-flight requests fail. The old token is retired only after the new one is proven in production. No token value is exposed in the process, since the credential lives in the secret store and never in source control or logs.
Store Tokens as Secrets, Not Source Code
Whether the integration uses PIT or OAuth, the credentials are secrets.
Do not commit them into Git.
Do not print them in logs.
Do not include them in screenshots.
Do not paste them into public tickets, chat messages, or documentation.
A production architecture should separate:
Application codefrom:
Authentication secretsFor OAuth, secrets can include:
- client secret;
- access token;
- refresh token.
For PIT, the token itself is sensitive.
The storage technology depends on the application, but the security requirement remains the same:
The application should be able to retrieve its credentials without unnecessarily exposing them to developers, logs, repositories, users, or unrelated tenants.
HighLevel credentials are treated as secrets, not configuration. Each location's token is stored in a dedicated secret store rather than in source control, loaded at runtime and keyed by location so the backend retrieves only the credential for the account it is acting on. Tokens never appear in logs, in the repository, or in the request payloads themselves. The store is the single place credentials live, which keeps rotation and revocation to one boundary rather than scattered copies.
Single-Location Integrations Are Where PIT Is Most Attractive
Consider an internal integration for one HighLevel Location:
Internal application
↓
PIT
↓
Location AThe company controls:
- the application;
- the HighLevel account;
- the token;
- the scopes;
- the deployment.
There is no external user who needs to click:
“Connect my HighLevel account.”
Building OAuth in this case might require:
- an installation page;
- redirect handling;
- an authorization callback;
- token exchange;
- refresh-token storage;
- installation records;
without solving an actual business requirement.
That is exactly where PIT simplicity becomes valuable.
OAuth Becomes More Valuable as the Installation Model Expands
Now consider a product used by many independent HighLevel customers:
Your application
│
├── Client A / Location A
├── Client B / Location B
├── Client C / Location C
└── Client D / Location DA PIT-based onboarding process might require every customer to:
- create a Private Integration;
- select the correct scopes;
- generate a token;
- send the token to your team or application;
- repeat the process when credentials change.
That may work technically.
But it becomes operationally awkward.
OAuth changes the onboarding flow:
Client
↓
Connect HighLevel
↓
Review requested permissions
↓
Authorize
↓
Application receives installation contextThis is why OAuth scales better as a product authorization flow.
The advantage is not that OAuth is more impressive technically.
The advantage is that customers can authorize the application through a standardized installation process.
Agency-Level and Location-Level Context Still Matter
Authentication does not remove HighLevel's account hierarchy.
Your application still needs to know which:
- Company/Agency;
- Location/Sub-Account;
the credential belongs to.
In a multi-location architecture, token context is part of tenant isolation.
Conceptually:
Incoming operation
↓
locationId
↓
installation record
↓
correct credential context
↓
HighLevel APIThe production rule is:
An operation for Client A should never execute with Client B's credential.
Avoid a design where the application stores one global OAuth token and uses it as a fallback for unrelated locations.
Authentication state should remain associated with the installation that created it.
This is especially important when one application manages many HighLevel accounts.
A candid note on a real limitation. This integration currently authenticates with a single Private Integration Token loaded from the environment. The code supports per-location tokens (it looks for a location-specific token first), but in practice one token has served the system while it operates against a single account. That is fine for one controlled location, but it is not a multi-tenant isolation model: a shared credential with a fallback is exactly what you should not carry into a system serving many independent locations, because an unmatched location silently uses the wrong token instead of failing. The correct design, and the direction this moves as more locations are added, is a distinct credential per location selected by locationId, with no fallback: if a location's token can't be resolved, the operation fails rather than borrowing another location's access.
When Does PIT Become the Wrong Abstraction?
PIT simplicity has a boundary.
Some warning signs are:
- customers manually sending credentials to your team;
- many independent clients needing separate manual setup;
- token rotation becoming recurring operational work;
- installation state being tracked manually;
- your product requiring Marketplace-style installation;
- customers needing to grant or revoke access themselves;
- app features depending on an installation lifecycle.
At that point, the problem is no longer simply:
“How can our backend authenticate?”
The real question becomes:
How should customers securely install and authorize our application?
That is where OAuth becomes the better abstraction.
When Is OAuth Unnecessary Complexity?
The opposite mistake also happens.
OAuth should not be added simply because it is the more familiar standard for third-party applications.
Consider:
One company
One backend
One controlled HighLevel account
No external installers
No public applicationThat environment may not need:
OAuth consent
redirect handling
authorization-code exchange
refresh logic
installation databaseA scoped PIT may be easier to implement and maintain.
The best architecture is not the one with the most authentication infrastructure.
It is the one that fits the ownership and installation model.
Common GoHighLevel Authentication Mistakes
Using a PIT for a Product Customers Need to Install
The API may work correctly, but customer onboarding becomes manual.
If independent customers need to connect their HighLevel accounts themselves, OAuth is usually a cleaner authorization boundary.
Building OAuth for One Internal Script
OAuth can work, but the installation and refresh infrastructure may provide no useful value.
A PIT may be enough.
Requesting Every Available Scope
More access does not make an integration better.
Request the minimum permissions required for the application.
Storing One OAuth Token Globally
This is dangerous in multi-location systems.
Credential state should remain associated with the correct HighLevel installation and account context.
Saving the New Access Token but Not the New Refresh Token
OAuth refresh is a state transition.
When new token values are returned, persist the new credential state correctly.
Treating Every 401 as Token Expiry
Inspect the authentication error first.
Do not refresh automatically when the actual problem is a missing, invalid, or revoked credential.
Treating PIT as Ordinary Configuration
A static token is still a secret.
Store and rotate it accordingly.
Following Legacy API-Key Tutorials
Modern PITs and older API keys are not the same authentication model.
Do not build a new production integration from an outdated authentication example.
GoHighLevel OAuth vs Private Integration: Decision Guide
A practical decision tree looks like this:
Who needs to authorize the integration?
↓
Only your own controlled environment?
/ \
Yes No
↓ ↓
Do customers Customers need
need an install to authorize your app
experience? ↓
/ \ OAuth
No Yes
↓ ↓
PIT OAuthChoose a Private Integration Token When
A PIT is usually a good starting point when:
- the integration is internal;
- you control the HighLevel environment;
- your team manages the credential;
- direct server-to-server access is enough;
- the integration normally targets one controlled account or location;
- no customer-facing installation flow is required.
Choose OAuth When
OAuth is usually a better fit when:
- customers connect their own HighLevel accounts;
- you are building an installable application;
- many independent HighLevel installations need to be managed;
- standardized authorization and revocation are important;
- Marketplace/application installation behavior is required;
- account/location authorization must happen without customers manually sharing API credentials.
Neither model is universally better.
They serve different integration models.
Can You Start With PIT and Move to OAuth Later?
Yes.
For some products, that is a sensible evolution.
An early prototype may use:
Development
↓
PIT
↓
HighLevel APIbecause the initial goal is to validate:
- API endpoints;
- payloads;
- application logic;
- required scopes.
If the integration later becomes a product that customers install, the authorization layer can evolve:
Internal prototype
↓
PIT
↓
Validate integration
↓
Multi-customer product
↓
OAuth installation modelWhat matters is recognizing when the product itself has changed.
Do not keep stretching an internal credential model after the integration becomes a customer-facing application.
A Production Authentication Architecture
A small internal PIT integration may only need:
Application
↓
Secure secret storage
↓
PIT
↓
HighLevel APIA multi-customer OAuth integration requires more:
HighLevel installation
↓
Authorization Code
↓
Token exchange
↓
Installation record
↓
Access Token
Refresh Token
Scopes
Location / Company context
↓
Secure token storage
↓
API client
↓
HighLevel APIThat additional complexity is justified because OAuth solves additional problems:
- delegated authorization;
- customer installation;
- token expiration;
- token refresh;
- installation identity;
- credential revocation;
- multi-tenant separation.
Do not copy the complexity of the second architecture into the first unless those requirements actually exist.
GoHighLevel Authentication Production Checklist
Before shipping the integration, confirm:
- Is this an internal integration or something customers install?
- Would a PIT satisfy the requirement without unnecessary OAuth infrastructure?
- If OAuth is used, is the authorization and redirect flow correct?
- Are only the required scopes requested?
- Is every credential tied to the correct HighLevel Company or Location?
- Are PITs, OAuth access tokens, refresh tokens, and client secrets stored securely?
- Can any credential accidentally reach source control or logs?
- Does OAuth refresh persist the complete new token state?
- Does the integration distinguish token expiry from other authentication failures?
- Is PIT rotation supported operationally?
- Can one customer's credential ever be used for another customer's location?
- Are legacy API-key examples being avoided?
- Has manual PIT onboarding become a bottleneck as the integration grows?
The right authentication model should make the integration safer and easier to operate, not simply more complicated.
Need Help Choosing the Right GoHighLevel Authentication Architecture?
Authentication problems often begin long before an API request returns 401.
The important decisions include:
- PIT or OAuth;
- required scopes;
- Company vs Location context;
- secure token storage;
- OAuth refresh handling;
- multi-client credential isolation;
- credential rotation;
- and whether an internal integration is becoming an installable product.
Hamza can review the integration and choose the smallest authentication architecture that safely matches the real use case.
For an internal tool, that may be a scoped Private Integration Token.
For a product installed by many HighLevel users, that may require a complete OAuth installation and token-management architecture.
Need help designing the authorization model? Work with a GoHighLevel developer for secure integrations
