Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
HighLevel API
https://github.com/gohighlevel/highlevel-api-docs
Admin
Official documentation for the GoHighLevel API V2, providing developers with structured references,
...
Tokens:
102,482
Snippets:
535
Trust Score:
8.1
Update:
6 days ago
Context
Skills
Chat
Benchmark
65.9
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# GoHighLevel API V2 Documentation GoHighLevel (HighLevel) API V2 is the official REST API for the HighLevel CRM and marketing platform, enabling third-party marketplace apps to programmatically manage contacts, calendars, conversations, opportunities, payments, invoices, workflows, users, sub-accounts, and more. All APIs are served from `https://services.leadconnectorhq.com` and authenticated via OAuth 2.0 bearer tokens. Every request requires a `Version` header (date-based, e.g. `2021-07-28` or `2021-04-15`) and returns a `traceId` in every response for debugging. Rate limits are enforced per app per resource: 100 requests per 10 seconds (burst) and 200,000 requests per day. The API surface consists of 41 OpenAPI 3.0 compliant modules (contacts, calendars, conversations, opportunities, payments, invoices, users, workflows, locations/sub-accounts, OAuth, etc.), a structured scopes system for access control, and a webhook event system for real-time notifications. Developers register an OAuth app on the HighLevel Marketplace, obtain `client_id` / `client_secret`, implement the Authorization Code Grant flow to receive access/refresh tokens, and then use those tokens as `Bearer` credentials. Webhook payloads are signed with an RSA public key (`x-wh-signature` header) and include a `timestamp` and `webhookId` to prevent replay attacks. --- ## OAuth 2.0 – Get Access Token Exchange an authorization code (received after user consent) for an access token and refresh token. Access tokens expire after 24 hours; refresh tokens are valid for 1 year and rotate on each use. ```bash # Step 1: Redirect user to authorization URL # https://marketplace.gohighlevel.com/oauth/chooselocation? # response_type=code& # redirect_uri=https://myapp.com/oauth/callback/gohighlevel& # client_id=CLIENT_ID& # scope=contacts.readonly contacts.write calendars.readonly # Step 2: Exchange the code for tokens curl --location 'https://services.leadconnectorhq.com/oauth/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=YOUR_CLIENT_ID' \ --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \ --data-urlencode 'grant_type=authorization_code' \ --data-urlencode 'code=7676cjcbdc6t76cdcbkjcd09821jknnkj' \ --data-urlencode 'redirect_uri=https://myapp.com/oauth/callback/gohighlevel' # Expected response: # { # "access_token": "eyJhbGciOi...", # "token_type": "Bearer", # "expires_in": 86400, # "refresh_token": "eyJhbGciOi...", # "scope": "contacts.readonly contacts.write", # "locationId": "ve9EPM428h8vShlRW1KT", # "userId": "abc123" # } # Step 3: Refresh expired token curl --location 'https://services.leadconnectorhq.com/oauth/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=YOUR_CLIENT_ID' \ --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \ --data-urlencode 'grant_type=refresh_token' \ --data-urlencode 'refresh_token=EXISTING_REFRESH_TOKEN' ``` --- ## OAuth 2.0 – Get Location Access Token from Agency Token Generate a sub-account (location) scoped access token from an agency-level token, useful for multi-location agency apps that need to act on behalf of specific sub-accounts. ```bash curl --location 'https://services.leadconnectorhq.com/oauth/locationToken' \ --header 'Version: 2021-07-28' \ --header 'Authorization: Bearer AGENCY_ACCESS_TOKEN' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'companyId=5DP41231LkQsiKESj6rh' \ --data-urlencode 'locationId=ve9EPM428h8vShlRW1KT' # Expected response: # { # "access_token": "eyJhbGciOi...", # "token_type": "Bearer", # "expires_in": 86400, # "locationId": "ve9EPM428h8vShlRW1KT" # } ``` --- ## Contacts – Search Contacts (Advanced) Search contacts using complex filter combinations including custom fields, tags, pipeline stages, date ranges, and more. Requires the `contacts.readonly` scope and the `Version: 2021-07-28` header. ```bash curl --location --request POST 'https://services.leadconnectorhq.com/contacts/search' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-07-28' \ --header 'Content-Type: application/json' \ --data-raw '{ "locationId": "ve9EPM428h8vShlRW1KT", "filters": [ { "field": "tags", "operator": "contains", "value": ["vip", "lead"] }, { "field": "email", "operator": "is_not_empty" } ], "sort": [ { "field": "dateAdded", "direction": "desc" } ], "pageSize": 25, "page": 1 }' # Response headers to watch: # X-RateLimit-Remaining: 97 # X-RateLimit-Daily-Remaining: 199975 ``` --- ## Contacts – Get Duplicate Contact Check for an existing contact by email or phone before creating a new one. Respects the sub-account's "Allow Duplicate Contact" setting. ```bash # Check by email (URL-encode special characters: test+abc@gmail.com → test%2Babc%40gmail.com) curl --location 'https://services.leadconnectorhq.com/contacts/search/duplicate?locationId=sadadya1u12basyhasd&email=test%2Babc%40gmail.com' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-07-28' # Check by phone (+1423164516 → %2B1423164516) curl --location 'https://services.leadconnectorhq.com/contacts/search/duplicate?locationId=sadadya1u12basyhasd&number=%2B14231645160' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-07-28' # 400 Bad Request if contact not found or bad params: # { "statusCode": 400, "message": "Bad Request", "error": "Bad Request" } ``` --- ## Contacts – Create Task for a Contact Create a task associated with a specific contact. Requires `contacts.write` scope. ```bash curl --location --request POST 'https://services.leadconnectorhq.com/contacts/sx6wyHhbFdRXh302LLNR/tasks' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-07-28' \ --header 'Content-Type: application/json' \ --data-raw '{ "title": "Follow-up call", "body": "Call to discuss proposal details", "dueDate": "2024-06-15T10:00:00.000Z", "completed": false, "assignedTo": "bNl8QNGXhIQJLv8eeASQ" }' # 201 Created response: # { # "task": { # "id": "ocQHyuzHvysMo5N5VsXc", # "title": "Follow-up call", # "body": "Call to discuss proposal details", # "dueDate": "2024-06-15T10:00:00.000Z", # "completed": false, # "assignedTo": "bNl8QNGXhIQJLv8eeASQ", # "contactId": "sx6wyHhbFdRXh302LLNR" # } # } ``` --- ## Calendars – Get Calendar Groups Retrieve all calendar groups within a sub-account location. Requires `calendars/groups.readonly` scope. ```bash curl --location 'https://services.leadconnectorhq.com/calendars/groups?locationId=ve9EPM428h8vShlRW1KT' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-04-15' # 200 response: # { # "groups": [ # { # "id": "BF4Wl5w4oFRTbcEtmrsu", # "locationId": "ve9EPM428h8vShlRW1KT", # "name": "Sales Team", # "slug": "sales-team", # "isActive": true # } # ] # } ``` --- ## Calendars – Create Appointment Book an appointment on a calendar. Requires `calendars/events.write` scope. ```bash curl --location --request POST 'https://services.leadconnectorhq.com/calendars/events/appointments' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-04-15' \ --header 'Content-Type: application/json' \ --data-raw '{ "calendarId": "CVokAlI8fgw4WYWoCtQz", "locationId": "ve9EPM428h8vShlRW1KT", "contactId": "9NkT25Vor1v4aToVODWs", "startTime": "2024-06-20T09:00:00+05:30", "endTime": "2024-06-20T09:30:00+05:30", "title": "Discovery Call", "appointmentStatus": "confirmed", "assignedUserId": "YlWd2wuCAZQzh2cH1fVZ", "notes": "Prospect interested in enterprise plan" }' # 201 Created: # { "id": "0TkCdp9PfvLeWKYRRvIz", "calendarId": "CVokAlI8fgw4WYWoCtQz", ... } ``` --- ## Opportunities – Search Opportunities Search pipeline opportunities with filters for pipeline, stage, status, assigned user, and date. Requires `opportunities.readonly` scope. ```bash curl --location 'https://services.leadconnectorhq.com/opportunities/search?location_id=i2SpAtBVHSVea1sL6oah&pipeline_id=bCkKGpDsyPP4peuKowkG&status=open&limit=20' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-07-28' # Response: # { # "opportunities": [ # { # "id": "wWhVuzqpRuOA1ZVWi4FC", # "name": "Enterprise Deal", # "monetaryValue": 5000, # "pipelineId": "bCkKGpDsyPP4peuKowkG", # "pipelineStageId": "e93ba61a-53b3-45e7-985a-c7732dbcdb69", # "status": "open", # "contactId": "cJAWDskpkJHbRbhAT7bs", # "assignedTo": "bNl8QNGXhIQJLv8eeASQ" # } # ], # "meta": { "total": 1, "currentPage": 1 } # } ``` --- ## Conversations – Search Conversations Search and filter conversation threads by contact, assignee, message type, or keyword. Requires `conversations.readonly` scope. ```bash curl --location 'https://services.leadconnectorhq.com/conversations/search?locationId=ABCHkzuJQ8ZMd4Te84GK&assignedTo=ABCHkzuJQ8ZMd4Te84GK&lastMessageType=TYPE_SMS&limit=20&sort=desc' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-04-15' # Supported lastMessageType values: # TYPE_CALL, TYPE_SMS, TYPE_RCS, TYPE_EMAIL, TYPE_WEBCHAT, # TYPE_SMS_REVIEW_REQUEST, TYPE_FB, TYPE_IG, TYPE_GMB, etc. # Response: # { # "conversations": [ # { # "id": "fcanlLgpbQgQhderivVs", # "contactId": "9VEmS0si86GW6gXWU89b", # "locationId": "ABCHkzuJQ8ZMd4Te84GK", # "lastMessageType": "TYPE_SMS", # "unreadCount": 3, # "dateUpdated": "2024-06-10T08:22:11.000Z" # } # ] # } ``` --- ## Invoices – Create Invoice Template Create a reusable invoice template for a sub-account or agency. Requires `invoices/template.write` scope. Supports both `Location-Access` and `Agency-Access` tokens. ```bash curl --location --request POST 'https://services.leadconnectorhq.com/invoices/template' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-07-28' \ --header 'Content-Type: application/json' \ --data-raw '{ "altId": "6578278e879ad2646715ba9c", "altType": "location", "name": "Standard Consulting Invoice", "currency": "USD", "items": [ { "name": "Consulting Services", "description": "Monthly retainer", "unitPrice": 2500, "quantity": 1, "taxes": [] } ], "discount": { "type": "percentage", "value": 10 }, "termsNotes": "Payment due within 30 days." }' ``` --- ## Payments – Create White-label Integration Provider Register a custom payment provider built on Authorize.net or NMI as a white-label integration. Can only be called using a marketplace-app token. Requires `payments/integration.write` scope. ```bash curl --location --request POST 'https://services.leadconnectorhq.com/payments/integrations/provider/whitelabel' \ --header 'Authorization: Bearer MARKETPLACE_APP_TOKEN' \ --header 'Version: 2021-07-28' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": "MyPayments Pro", "description": "Custom NMI-based payment provider", "paymentsGateway": "NMI", "credentials": { "apiKey": "nmi-api-key-here" }, "locationId": "ve9EPM428h8vShlRW1KT" }' ``` --- ## Users – Search Users Search for agency or sub-account users by name, email, phone, role, or location. Requires `users.readonly` scope. ```bash curl --location 'https://services.leadconnectorhq.com/users/search?companyId=5DP41231LkQsiKESj6rh&query=John&role=admin&type=agency&limit=10&skip=0&sort=dateAdded&sortDirection=asc' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-07-28' # Filter multiple users by IDs: curl --location 'https://services.leadconnectorhq.com/users/search?companyId=5DP41231LkQsiKESj6rh&ids=5DP4iH6HLkQsiKESj6rh,5DP4iH6HLkQsiKESj34h' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-07-28' ``` --- ## Workflows – Get Workflows List all automation workflows for a sub-account location. Requires `workflows.readonly` scope. ```bash curl --location 'https://services.leadconnectorhq.com/workflows/?locationId=ve9EPM428h8vShlRW1KT' \ --header 'Authorization: Bearer ACCESS_TOKEN' \ --header 'Version: 2021-07-28' # Response: # { # "workflows": [ # { # "id": "78559bb3-b920-461e-b010-7b2a2816d2a6", # "name": "Lead Nurture Sequence", # "status": "published", # "locationId": "ve9EPM428h8vShlRW1KT", # "createdAt": "2023-03-15T08:00:00.000Z", # "updatedAt": "2024-01-10T14:30:00.000Z" # } # ] # } ``` --- ## External Billing Webhook For marketplace apps with external billing enabled, notify HighLevel of payment completion or failure after the user is redirected to your billing URL. Authentication uses `x-ghl-client-key` and `x-ghl-client-secret` headers. ```bash curl --location 'https://services.leadconnectorhq.com/oauth/billing/webhook' \ --header 'x-ghl-client-key: YOUR_CLIENT_KEY' \ --header 'x-ghl-client-secret: YOUR_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data-raw '{ "clientId": "YOUR_CLIENT_ID", "authType": "location", "locationId": "ve9EPM428h8vShlRW1KT", "subscriptionId": "sub_1234567890", "paymentId": "pay_abc123", "amount": 99, "status": "COMPLETED", "paymentType": "recurring" }' # For agency-level billing: # { "authType": "company", "companyId": "5DP41231LkQsiKESj6rh", ... } # Trigger separately for each location — batch billing is not supported. ``` --- ## Webhook Event – ContactCreate Fired when a new contact is created in a sub-account. Subscribe via Marketplace app settings with the `contacts.readonly` scope. Validate using `x-wh-signature` header. ```javascript // Node.js Express webhook receiver with signature verification const crypto = require('crypto'); const express = require('express'); const app = express(); app.use(express.json()); const GHL_PUBLIC_KEY = `-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAokvo/r9tVgcfZ5DysOSC Frm602qYV0MaAiNnX9O8KxMbiyRKWeL9JpCpVpt4XHIcBOK4u3cLSqJGOLaPuXw6 ... -----END PUBLIC KEY-----`; app.post('/webhooks/ghl', (req, res) => { const signature = req.headers['x-wh-signature']; const payload = JSON.stringify(req.body); // Verify signature const verifier = crypto.createVerify('SHA256'); verifier.update(payload); const isValid = verifier.verify(GHL_PUBLIC_KEY, signature, 'base64'); if (!isValid) return res.status(401).send('Invalid signature'); // Replay attack protection const { timestamp, webhookId } = req.body; const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000); if (new Date(timestamp) < fiveMinutesAgo) return res.status(400).send('Stale webhook'); // Handle events const event = req.body; if (event.type === 'ContactCreate') { // event.id, event.locationId, event.email, event.firstName, event.tags, etc. console.log('New contact:', event.id, event.email); // Example payload: // { // "type": "ContactCreate", // "locationId": "ve9EPM428h8vShlRW1KT", // "id": "nmFmQEsNgz6AVpgLVUJ0", // "email": "JohnDeo@gmail.com", // "name": "John Deo", // "phone": "+919509597501", // "tags": ["vip", "lead"], // "customFields": [{ "id": "BcdmQEsNgz6AVpgLVUJ0", "value": "XYZ Corp" }] // } } if (event.type === 'InboundMessage') { // event.messageType: SMS, Email, CALL, FB, IG, GMB, etc. // event.conversationId, event.contactId, event.body, event.callDuration console.log('Inbound message via', event.messageType, 'from', event.contactId); } if (event.type === 'OpportunityCreate') { // event.pipelineId, event.pipelineStageId, event.monetaryValue, event.status console.log('New opportunity:', event.name, '$' + event.monetaryValue); } if (event.type === 'INSTALL') { // event.appId, event.locationId, event.companyId, event.planId, event.trial console.log('App installed at location:', event.locationId); } res.status(200).send('OK'); }); app.listen(3000); ``` --- ## Webhook Event – AppInstall / AppUninstall Fired when a marketplace app is installed or uninstalled at the agency or location level. Includes trial details and white-label branding information. ```json // Location-level install for a white-labeled company: { "type": "INSTALL", "appId": "ve9EPM428h8vShlRW1KT", "locationId": "otg8dTQqGLh3Q6iQI55w", "companyId": "otg8dTQqGLh3Q6iQI55w", "userId": "otg8dTQqGLh3Q6iQI55w", "planId": "66a0419a0dffa47fb5f8b22f", "trial": { "onTrial": true, "trialDuration": 10, "trialStartDate": "2024-07-23T23:54:51.264Z" }, "isWhitelabelCompany": true, "whitelabelDetails": { "domain": "example.com", "logoUrl": "https://example.com/logo.png" }, "companyName": "Example Company" } // Agency-level install (no locationId/userId): { "type": "INSTALL", "appId": "ve9EPM428h8vShlRW1KT", "companyId": "otg8dTQqGLh3Q6iQI55w", "planId": "66a0419a0dffa47fb5f8b22f", "trial": { "onTrial": false } } ``` --- ## Rate Limit Handling Every API response includes rate limit headers. The recommended pattern is to check these headers and back off when limits are close. ```javascript async function callGHL(url, options) { const res = await fetch(`https://services.leadconnectorhq.com${url}`, { ...options, headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}`, 'Version': '2021-07-28', 'Content-Type': 'application/json', ...options.headers, }, }); // Log rate limit state console.log('Burst remaining:', res.headers.get('X-RateLimit-Remaining')); console.log('Daily remaining:', res.headers.get('X-RateLimit-Daily-Remaining')); if (res.status === 429) { const retryAfterMs = parseInt(res.headers.get('X-RateLimit-Interval-Milliseconds') || '10000'); console.warn(`Rate limited. Retrying after ${retryAfterMs}ms`); await new Promise(r => setTimeout(r, retryAfterMs)); return callGHL(url, options); // retry once } if (res.status === 401) { // Token expired — refresh and retry await refreshAccessToken(); return callGHL(url, { ...options, headers: { Authorization: `Bearer ${NEW_ACCESS_TOKEN}` } }); } return res.json(); } // Usage: const contact = await callGHL('/contacts/sx6wyHhbFdRXh302LLNR', { method: 'GET' }); ``` --- The GoHighLevel API V2 is primarily used to build marketplace apps that extend the HighLevel CRM platform for agencies and their clients (sub-accounts). Common use cases include: syncing CRM contacts from external sources (e-commerce platforms, forms, event systems) using the Contacts API; automating appointment scheduling via the Calendars API; building conversation inbox integrations for SMS, email, and social channels via the Conversations API; managing sales pipelines programmatically using the Opportunities API; and collecting recurring revenue for marketplace apps via the Payments and external Billing webhook. The webhook event system enables real-time reactive workflows—triggering fulfillment on `InvoicePaid`, onboarding sequences on `ContactCreate`, or provisioning resources on app `INSTALL`. Integration typically follows a three-layer architecture: (1) OAuth flow to obtain and securely store per-location access/refresh token pairs; (2) versioned REST API calls with bearer auth and date-based `Version` headers, with retry/refresh logic wrapping all requests; and (3) a webhook receiver that verifies RSA signatures, rejects replays, and fans out events to internal handlers. For agency-scale apps managing multiple sub-accounts, the `GET /oauth/locationToken` endpoint allows a single agency token to mint scoped location tokens on-demand, avoiding storing individual tokens per location. All scopes are granular (e.g., `contacts.readonly`, `calendars/events.write`, `invoices/template.write`) and must be declared when registering the OAuth app in the HighLevel Marketplace.