
10 Things to Do When Building HighLevel Integrations in 2026
HighLevel now powers over 1 million businesses globally (HighLevel 2025 Year in Review), and the marketplace has crossed 1,500 published apps. That is not a hobby ecosystem anymore. Developers and agencies who build integrations well are generating real revenue — HighLevel offers a 15% share on paid marketplace app installs (help.gohighlevel.com). But the platform moves fast: over 2,300 user-facing releases shipped in 2025 alone. Getting the fundamentals wrong costs you time, installs, and trust.
These 10 things separate integrations that hold up in production from the ones that break quietly on a Saturday morning.
TL;DR: Pick OAuth for marketplace apps, Private Tokens for internal tools. Store every refresh token. Deduplicate webhooks by webhookId. Paginate everything. Scope down your permissions. Migrate to Ed25519 webhook signatures before July 1, 2026. Instrument early — GHL support does not debug your code.
1. Choose Your Integration Type Before Writing a Single Line of Code
The single most important architectural decision is which of HighLevel's two integration paths you use — and it changes everything downstream. Private Integration Tokens are static, scoped to a single location, and have no webhook support or OAuth flow. OAuth 2.0 is required for marketplace listing, supports webhooks, and handles multi-location token management. Getting this wrong means a full rebuild.
Private Tokens are fine for internal agency tools where you control one account. The moment you need to distribute your app to other sub-accounts or list it on the marketplace — where over 1,500 apps now compete — you need OAuth. Make the call before you write your first API request.
2. Design for Multi-Tenancy From the Start
Every sub-account in HighLevel is a distinct entity with its own token. Store tokens per locationId — never share a token across locations. Using an agency-level token directly on sub-account endpoints returns a 403. The platform intentionally enforces this boundary.
The App Install webhook payload gives you what you need: locationId, companyId, isWhitelabelCompany, and an isBulkInstallation flag. When isBulkInstallation is true, an agency has installed your app across multiple locations at once — iterate that list and exchange the agency token for a location-scoped token for each one via GET /oauth/locationToken?locationId=X&companyId=Y. One missed location means a broken install someone will churn over.
Also: userId may be absent in install webhook payloads for future-location installs. Write defensive code that handles a missing userId without crashing your install handler.
3. Treat the Refresh Token as Precious — Store Every New One
HighLevel access tokens expire after 24 hours. Refresh tokens expire after one year — or upon use, whichever comes first. That second condition catches developers constantly. Refresh tokens are single-use. The moment you use one, it is invalidated and a new one is issued.
If you store only the access token and discard the refresh token, your users lose access the next morning. Your storage logic must write both the new access_token and the new refresh_token atomically every time a refresh occurs. This is not a race condition to handle later — it is day-one database schema thinking.
4. Migrate Your Webhook Signatures Before July 1, 2026
HighLevel is deprecating the X-WH-Signature header (RSA-SHA256) on July 1, 2026. The new standard is X-GHL-Signature, which uses Ed25519. If your integration was built before mid-2025, you are almost certainly still validating the old header. After July 1, those validations will silently fail or stop arriving.
Ed25519 is faster and more secure than RSA-SHA256. Switching is a one-time change in your webhook verification middleware. Both headers are present during the transition window — deploy the new validation logic now, verify it in parallel, and remove the RSA fallback before the cutoff. Do not treat this as a Q4 problem.
Roughly 20% of webhook events fail in production despite sandbox testing (Hookdeck, industry estimate). Signature mismatches add to that number. Fix the known ones first.
5. Build Idempotent Webhook Handlers Using webhookId Deduplication
HighLevel retries webhook delivery up to 6 times, spaced roughly 10 minutes apart, over a window of about 70 minutes. Retries are triggered by HTTP 429 responses only — not 5xx. If your endpoint crashes with a 500, GHL marks it final and does not retry. But if you return a 429, it will keep trying.
The correct pattern: return HTTP 200 immediately, then process the event asynchronously. Store the webhookId from each incoming payload before processing and check for duplicates before acting. Without this, you will create duplicate contacts, fire duplicate automations, and have a very bad time explaining to a client why they got three confirmation emails.
Stripe's idempotency guidance (stripe.com/blog) applies equally here — use a UUID with sufficient entropy as your deduplication key, backed by persistent storage, not in-memory cache.
6. Never Assume Page 1 Is All Your Data
Pagination in HighLevel is not consistent across endpoints. Contacts use cursor-based pagination via startAfter and startAfterId query parameters, with a default page size of 20 and a max of 100 per request. Other endpoints use page and limit. Some use resource-specific cursors you have to read the docs for individually.
The dangerous part is the failure mode: fetching only the first page does not throw an error. You get a 200, you get data, and you have no idea you missed 90% of the contact list. This is silent data loss. HighLevel executed 120 billion workflow actions in 2024 (HighLevel 2024 Recap) — the data volumes at active accounts are not trivial. Build a pagination loop from the start, not as a fix after a client notices missing records.
7. Request Only the Scopes You Actually Need
HighLevel's OAuth consent screen displays a bold security warning when your app requests sensitive scopes like users.write or locations.write. That warning is visible to every agency owner who installs your app. It directly reduces install conversion.
Scope down to the minimum your integration requires. If you only read contacts, request contacts.readonly. The pattern is resource.readonly for read access and resource.write for full access. Overly broad scopes also flag your app during marketplace review and can delay approval. Start with least-privilege from day one — adding a scope later requires users to re-authorize, which is a friction point most will not bother with.
8. Respect Rate Limits Architecturally, Not Just Reactively
HighLevel's v2 API enforces a burst limit of 100 requests per 10 seconds per app per resource, and a daily cap of 200,000 requests per day per app per resource (HighLevel developer docs). Watch the X-RateLimit-Remaining and X-RateLimit-Daily-Remaining response headers on every call. When you hit a 429, the correct backoff is 500ms → 1s → 2s, up to 3 retries, with ±20% jitter (ghllogic.com).
Do not bolt rate limit handling onto your HTTP client as an afterthought. Design your job queues and sync pipelines to spread requests over time. A bulk contact import that fires 500 requests in two seconds will get throttled and fail every time.
9. Handle White-Label Context in Every User-Facing Surface
Many HighLevel agencies resell the platform under their own brand. When your app is installed by a white-label agency, the install webhook payload includes isWhitelabelCompany: true and a whitelabelDetails object with their custom domain and logo URL. Surfacing "GoHighLevel" or "HighLevel" branding inside that environment violates the agency's client agreement.
This is not a cosmetic concern. Agencies pay for the white-label privilege and protect it seriously. If your app's UI, error messages, documentation links, or email notifications reference HighLevel directly — and a white-label client sees it — you put the agency in an awkward position and risk losing the install. Check isWhitelabelCompany at runtime and conditionally suppress platform references.
10. Instrument Your Integration — GHL Support Won't Debug It for You
HighLevel executed 4.5 million workflows and 120 billion workflow actions in 2024 (HighLevel 2024 Recap). At that scale, their support organization is not resourced to diagnose why your OAuth token isn't refreshing or why your webhook handler is dropping events. That debugging falls on you.
Log every API request with its response code, the locationId, and a timestamp. Log every webhook receipt with the webhookId before you do anything else. Track refresh token exchanges and flag failures immediately. Set up alerting on 429 spikes and on refresh failures that would lock a user out. The integrations that survive long-term are the ones where the developer knows about a problem before the client does.
Integration Type Comparison
| Feature | Private Integration Token | OAuth 2.0 Marketplace App |
|---|---|---|
| Multi-account support | No — single location only | Yes — per-location token exchange |
| Webhook support | No | Yes |
| Token rotation | Static (no automatic expiry) | Access: 24hr; Refresh: 1yr or on use |
| Marketplace eligible | No | Yes |
| Best for | Internal agency tools, single-account automation | Distributable apps, marketplace listing, multi-location use |
Frequently Asked Questions
Do I need OAuth to publish on the HighLevel Marketplace?
Yes. OAuth 2.0 is required for all marketplace-listed apps. Private Integration Tokens do not support the webhook and multi-location token flows that the marketplace infrastructure depends on. If you start with a Private Token and want to list your app later, you will need to rebuild the auth layer.
What happens if my webhook endpoint returns a 500 error?
HighLevel treats 5xx responses as final — no retry is triggered. Retries only fire on HTTP 429 responses, up to 6 times over roughly 70 minutes. If your handler crashes with a 500, that webhook event is gone. Return 200 immediately and process asynchronously to avoid this situation entirely.
Can I use one token for multiple sub-accounts?
No. Tokens are scoped to a single locationId. Using an agency-level access token directly on sub-account API endpoints returns a 403. For multi-location access, exchange the agency token for a location-specific token via GET /oauth/locationToken?locationId=X&companyId=Y for each location you need to act on.
How do I test my HighLevel integration before going live?
HighLevel provides a developer sandbox environment accessible through your developer account. Use it to test the full OAuth flow, webhook delivery, and token refresh behavior before connecting production accounts. Also test edge cases explicitly: bulk install payloads, missing userId fields in install webhooks, and pagination across endpoints with more than 20 records.
Conclusion
HighLevel's growth — 781% over three years (Inc. 5000) — means the integration opportunity is real. But the platform expects your code to be production-grade. Get the architecture right early: OAuth vs. Private Token, per-location storage, idempotent webhooks, full pagination, and minimal scopes. Migrate your webhook signatures before July 1. Log everything. The developers building durable integrations on HighLevel are the ones who treat these fundamentals as non-negotiable from day one.
