SCOPENINE

GoHighLevel API

GoHighLevel API:A practical guide for agencies

Last checked: October 2026

The GoHighLevel (GHL) API lets your code read and write GHL data: contacts, opportunities, calendars, conversations and more. To use it, create a Private Integration token or an OAuth app, then call services.leadconnectorhq.com with two headers.

Those headers are Authorization and Version. For new builds, GHL's docs point you to Version: v3.

Where to find the GoHighLevel API documentation

GHL's official reference is the HighLevel API documentation. It opens on v3, and each endpoint page lists the scope and headers that call needs.

The developer portal, developers.gohighlevel.com, also still links the old API 1.0 docs, so check which set you are reading.

GoHighLevel API v1, v2 and v3: what is current

GHL uses three labels, and they mean different things.

  • API v1 is the old API that used API keys. GHL says it reached end of support on December 31, 2025. Old v1 integrations still run, but get no support or updates.
  • API v2 (API 2.0) is what GHL's help center calls the current OAuth-based API. It runs at services.leadconnectorhq.com.
  • v3 is the newest Version header value, released June 11, 2026. Older values are dates, such as 2021-07-28.

What changed in v3

GHL's help center says "API v3 is now available for supported endpoints." So check each endpoint page for the Version value it accepts.

The v3 reference shows four things:

  • Same base URL and tokens. v3 pages accept a sub-account OAuth token or a sub-account Private Integration token.
  • Mostly the same paths. Contact, calendar event and opportunity search paths stay the same. The location token call moved from /oauth/locationToken to /oauth/location-token.
  • Some new parameter names. Opportunity search takes location_id in 2021-07-28, but locationId in v3.
  • A new response format. GHL's v3 overview pages say v3 uses a new response style, so some responses differ from 2021-07-28. Compare each response before you switch.

What agencies should use now

For new builds, send Version: v3 on every endpoint that lists it. Copy the value from the endpoint page.

For existing builds on 2021-07-28, there is no deadline yet. GHL's versioning page lists every older version's end date as TBD. Still, the 2021-07-28 docs now say they are "no longer actively maintained."

Once GHL retires a version, it rejects requests that send it. GHL recommends moving to the latest version before that date. Test each call on v3 first, since responses can differ.

Two ways to authenticate

GHL supports two types of authorization: Private Integration tokens and OAuth 2.0. Both send the token as Authorization: Bearer <token>.

Private Integration tokens: internal tools, one sub-account

A Private Integration token is a static OAuth2 access token that you create inside GHL. GHL suggests it for internal jobs, such as data sync, reporting dashboards and automated tasks. It fits when you need one sub-account at a time and no webhooks.

To create one:

  1. 01Open Settings → Private Integrations in the agency or a sub-account. If the agency menu lacks it, turn it on in Labs.
  2. 02Create a new integration and give it a name and description.
  3. 03Select only the scopes it needs.
  4. 04Copy the token right away. GHL shows it only once.

GHL allows up to 20 tokens at the agency level, and 20 at the sub-account level. Tokens do not refresh on their own, and GHL recommends rotating them every 90 days.

"Rotate and expire this token later" keeps old and new tokens working for 7 days. If a token leaks, choose "Rotate and expire this token now."

OAuth 2.0 marketplace apps: many sub-accounts, webhooks, public apps

Use OAuth 2.0 when one integration serves many sub-accounts, needs webhooks or will go public.

The flow:

  1. 01Create an app in the GHL Marketplace. GHL recommends starting it as Private.
  2. 02Set scopes and a redirect URL, then generate a Client ID and Client Secret. GHL shows the secret only once.
  3. 03Install the app from its Installation URL. GHL redirects to your URL with a code query parameter.
  4. 04POST that code to /oauth/token with your client ID and secret, grant_type=authorization_code and a user_type. The v3 reference also requires Version: v3 on this call.

Access tokens last about a day (expires_in is 86399 seconds). Refresh tokens last up to a year, or until used. Each refresh returns a new refresh token and ends the old one.

Company (agency) tokens call agency APIs, such as creating sub-accounts. Location tokens call sub-account APIs, such as contacts.

To turn a Company token into a Location token, call POST /oauth/location-token with companyId and locationId. In v3, this call needs the oauth.write scope and does not accept Private Integration tokens.

Which one should you pick?

Your jobUse
Sync one client's CRM to a dashboardPrivate Integration token
Run one integration across many sub-accountsOAuth marketplace app
Receive events such as ContactCreateOAuth marketplace app
Add custom workflow actions or triggersOAuth marketplace app

GHL API base URL, headers and a first request

Requests go to https://services.leadconnectorhq.com. Send these headers:

  • Authorization: Bearer <token>
  • Version: v3, or the value the endpoint page lists
  • Content-Type: application/json when you send a body

Many sub-account calls also need the sub-account's ID, usually as locationId. Find it under Settings → Business Profile, or in the browser URL after /location/.

Example: upsert a contact with a Private Integration token

This call creates a contact or updates a match. It needs the contacts.write scope and sends Version: v3. Heads-up: GHL's Private Integrations page still shows 2021-07-28 in its examples.

bash
curl -X POST 'https://services.leadconnectorhq.com/contacts/upsert' \
  -H 'Authorization: Bearer YOUR_PRIVATE_INTEGRATION_TOKEN' \
  -H 'Version: v3' \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "locationId": "YOUR_LOCATION_ID",
    "firstName": "Jane",
    "email": "[email protected]",
    "phone": "+15555550123",
    "source": "website form"
  }'

For a simple read test, try GET /contacts/{contactId} with the contacts.readonly scope.

The main objects

ObjectWhat you can doExample
ContactsCreate, get, update, delete, upsert and search, plus tags, notes and tasksPOST /contacts/upsert (contacts.write)
OpportunitiesCreate, update, upsert, change status and search; manage pipelinesGET /opportunities/search (opportunities.readonly)
CalendarsCalendars, groups, appointments, blocked slots and availabilityGET /calendars/events (calendars/events.readonly)
ConversationsCreate and read conversations, send messages, add inbound messages, upload attachments"Send a new message"
Custom fieldsCreate, update and delete fields and folders; list fields by object keyCustom Fields V2 API
Custom objectsSchemas for contact, opportunity, business and custom objects; records for business and custom objectsObjects API
WebhooksReal-time events, 50+ typesContactCreate, ContactUpdate

GoHighLevel API rate limits

GHL's rate limits page covers API 2.0 calls made with OAuth:

  • Burst: 100 requests per 10 seconds
  • Daily: 200,000 requests per day

Limits count per marketplace app, per resource. A resource is one sub-account (Location) or one agency (Company). More installs do not split your allowance, because each install gets its own budget.

Each response carries headers that show where you stand:

HeaderWhat it tells you
X-RateLimit-Limit-DailyYour daily limit
X-RateLimit-Daily-RemainingRequests left today
X-RateLimit-Interval-MillisecondsLength of the burst window
X-RateLimit-MaxMost requests allowed per burst window
X-RateLimit-RemainingRequests left in the current window

GHL says to read these headers instead of counting requests yourself. Slow down as X-RateLimit-Remaining nears zero.

Webhooks: marketplace apps vs workflow webhooks

GHL has two kinds of webhooks, and they solve different problems.

Marketplace app webhooks

These send events, such as ContactCreate, to your server for each sub-account that installs your app. They need an OAuth app, since GHL steers Private Integration tokens toward jobs without webhooks.

First, add the scopes your events need. Then open the webhook section under Advanced Settings, turn on each event and paste your URL. Events and URLs can change at any time, but scopes change only in a draft version.

Three rules from GHL's webhook guide keep delivery healthy:

  • Verify signatures. Check X-GHL-Signature (Ed25519) and reject requests that fail. GHL gave September 1, 2026 as the deprecation date for the legacy X-WH-Signature.
  • Reply fast. Return a 2xx right away and do heavy work in the background. GHL retries a non-2xx or missing response up to 12 times.
  • Watch your success rate. GHL checks URLs that get over 10,000 webhooks in 3 days. Below 90% success, you get a warning. Fail the next check, and delivery pauses.

A timeout can trigger a retry of work you already did. Make your handler safe to run twice.

Workflow webhooks

These are workflow actions and triggers inside one sub-account.

  • Webhook (Outbound) action: sends contact data to a URL, by POST by default.
  • Custom Webhook action: sends GET, POST, PUT or DELETE requests, with Bearer, API key, Basic Auth or OAuth2.
  • Inbound Webhook trigger: starts a workflow when another system sends JSON to the trigger's own URL.

GHL calls Inbound Webhook a premium trigger. Each sub-account gets 100 free executions, so check GHL's premium trigger article for costs past that.

Use workflow webhooks for logic inside one account. Use marketplace webhooks when your code must hear from many accounts.

Common mistakes, and how to avoid them

Using the wrong token or location

The Contacts, Calendars, Conversations and Opportunities docs call for a sub-account token. That means a Location OAuth token or a sub-account Private Integration token.

Holding a Company token? Exchange it at the location token endpoint first. Then send the locationId of the sub-account that token belongs to.

Missing scopes

Endpoint pages list the scope each call needs, such as contacts.readonly to read a contact. You can edit a Private Integration's scopes, and the token keeps working. A live marketplace app needs a new draft first.

Letting tokens expire

OAuth access tokens last a day. After each refresh, save both the new access token and the new refresh token. GHL suggests one wrapper for every call: send, refresh on expiry, save, retry.

Creating duplicate contacts

Use upsert for form and sync traffic. It follows the sub-account's "Allow Duplicate Contact" setting, under Settings → Business Profile → Contact Deduplication Preferences.

To check first, call GET /contacts/search/duplicate with locationId, plus email or number.

Ignoring pagination

Opportunity search takes limit (default 20, max 100) and page. Its meta object returns startAfter, startAfterId and nextPageUrl for the next page.

The 2021-07-28 docs mark GET /contacts/ as deprecated. Use Search Contacts, POST /contacts/search, instead.

Straight answers

Which GoHighLevel API version should I use?
For new builds, use the current API with Version: v3 on endpoints that list it. GHL released v3 on June 11, 2026.API v1 reached end of support on December 31, 2025. Version 2021-07-28 is still listed as supported, but its docs are no longer actively maintained.
Where do I find my GoHighLevel API key?
New builds use a Private Integration token. API v1 reached end of support on December 31, 2025, and GHL is phasing out new v1 keys. Create one under Settings → Private Integrations. Copy it right away, because GHL shows it only once.
Do I need a GoHighLevel developer account to use the API?
Not for a Private Integration token, which you create inside GHL. For an OAuth app, GHL's app guide starts with a developer account in the GHL Marketplace.
Which GHL plans include API access?
GHL's API article says Starter and Unlimited include basic API access, but its pricing page lists it only on Unlimited. Agency Pro adds advanced access, with OAuth and agency-level tokens. Enterprise customers can request a higher API limit.
Can a Private Integration token receive webhooks?
GHL's docs point you to OAuth when an integration needs webhooks. Inside one sub-account, a workflow webhook action can still post data to your URL.

Need help with a GHL API build?

Scope Nine is a white-label engineering studio for marketing agencies. We build custom GHL integrations under your agency's brand.

Need code beyond what GHL ships? Work with a GHL developer who knows the platform.

Founder Abdullah Sajjad is a senior full-stack developer in Toptal's top 3%, with 8+ years and 250+ delivered projects. He works in GHL, WordPress, Next.js, HubSpot integrations and API-driven automation.

Start with a free technical audit. One-off builds fit a Client Delivery Sprint, from $999 one-time. Ongoing work fits an Embedded Delivery Pod, from $4,000/month.

You can also see our white-label GHL services or hire a GHL expert.

Chat on WhatsApp