GoHighLevel

v1.0.0

GoHighLevel (Private Integration Token) API integration with managed auth. CRM, sales pipelines, calendars, conversations, payments, and marketing automation...

0· 30· 1 versions· 0 current· 0 all-time· Updated 5h ago· MIT-0

Install

openclaw skills install highlevel-api

GoHighLevel (Private Integration Token)

Access the GoHighLevel API with managed Private Integration Token (PIT) authentication. Manage contacts, sales pipelines, calendars, conversations, invoices, products, businesses, and marketing automation.

Important: Two Token Types

GoHighLevel uses two types of Private Integration Tokens with different scopes:

Token TypePurposeKey Capabilities
AgencyManage the agency and its sub-accounts (locations)Search/create/update/delete locations, manage snapshots
Sub-AccountOperate within a specific locationContacts, calendars, pipelines, conversations, payments, custom fields, tags, workflows, campaigns

You will typically need both connections — an agency token for location management and a sub-account token for CRM operations. Use the Maton-Connection header to specify which token to use for each request.

Quick Start

# List contacts (Sub-Account token)
curl -s -X GET "https://api.maton.ai/highlevel-pit/contacts/?locationId={locationId}&limit=10" \
  -H "Authorization: Bearer $MATON_API_KEY"

Base URL

https://api.maton.ai/highlevel-pit/{resource}

Maton proxies requests to services.leadconnectorhq.com and automatically injects your PIT token.

Authentication

All requests require the Maton API key in the Authorization header:

Authorization: Bearer $MATON_API_KEY

Environment Variable: Set your API key as MATON_API_KEY:

export MATON_API_KEY="YOUR_API_KEY"

Getting Your API Key

  1. Sign in or create an account at maton.ai
  2. Go to maton.ai/settings
  3. Copy your API key

Connection Management

Manage your GoHighLevel PIT connections at https://api.maton.ai.

List Connections

curl -s -X GET "https://api.maton.ai/connections?app=highlevel-pit&status=ACTIVE" \
  -H "Authorization: Bearer $MATON_API_KEY"

Create Connection

curl -s -X POST "https://api.maton.ai/connections" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $MATON_API_KEY" \
  -d '{"app": "highlevel-pit"}'

Open the returned url in a browser to enter your Private Integration Token.

Get Connection

curl -s -X GET "https://api.maton.ai/connections/{connection_id}" \
  -H "Authorization: Bearer $MATON_API_KEY"

Response:

{
  "connection": {
    "connection_id": "{connection_id}",
    "status": "ACTIVE",
    "app": "highlevel-pit",
    "method": "API_KEY"
  }
}

Delete Connection

curl -s -X DELETE "https://api.maton.ai/connections/{connection_id}" \
  -H "Authorization: Bearer $MATON_API_KEY"

Specifying Connection

Since you will typically have two connections (agency + sub-account), always specify which one to use:

curl -s -X GET "https://api.maton.ai/highlevel-pit/contacts/?locationId={locationId}" \
  -H "Authorization: Bearer $MATON_API_KEY" \
  -H "Maton-Connection: {connection_id}"

If you have multiple connections, always include this header to ensure requests go to the intended account.

Security & Permissions

  • Access is scoped to locations, contacts, opportunities, calendars, conversations, workflows, and CRM data within the connected GoHighLevel account.
  • Two token types with different scopes: Agency tokens manage locations and snapshots. Sub-Account tokens access contacts, calendars, pipelines, and CRM data. Use the correct connection for the intended scope.
  • All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.

API Reference — Agency Token

These endpoints require an Agency token.

Locations (Sub-Accounts)

Search Locations

GET /highlevel-pit/locations/search?companyId={companyId}

Query parameters:

  • companyId (required) - The agency's company ID
  • limit - Results per page
  • skip - Number to skip (offset)
  • order - Sort order
  • email - Filter by email

Response:

{
  "locations": [
    {
      "id": "abc123",
      "companyId": "xyz789",
      "name": "My Sub-Account",
      "address": "123 Main St",
      "city": "San Francisco",
      "state": "CA",
      "country": "US",
      "postalCode": "94105",
      "timezone": "America/Los_Angeles",
      "email": "admin@example.com",
      "phone": "+15551234567"
    }
  ]
}

Get Location

GET /highlevel-pit/locations/{locationId}

Response:

{
  "location": {
    "id": "abc123",
    "name": "My Sub-Account",
    "address": "123 Main St",
    "city": "San Francisco",
    "state": "CA",
    "settings": {
      "allowDuplicateContact": false,
      "allowDuplicateOpportunity": false
    },
    "social": { ... },
    "permissions": { ... }
  }
}

Create Location

POST /highlevel-pit/locations/
Content-Type: application/json

{
  "companyId": "{companyId}",
  "name": "New Sub-Account",
  "address": "123 Main St",
  "city": "San Francisco",
  "state": "CA",
  "postalCode": "94105",
  "country": "US",
  "timezone": "America/Los_Angeles",
  "email": "admin@example.com",
  "phone": "+15551234567"
}

Update Location

PUT /highlevel-pit/locations/{locationId}
Content-Type: application/json

{
  "name": "Updated Name",
  "city": "Los Angeles"
}

Delete Location

DELETE /highlevel-pit/locations/{locationId}

Snapshots

List Snapshots

GET /highlevel-pit/snapshots/?companyId={companyId}

API Reference — Sub-Account Token

These endpoints require a Sub-Account token. Most endpoints require a locationId query parameter.

Contacts

List Contacts

GET /highlevel-pit/contacts/?locationId={locationId}

Query parameters:

  • locationId (required)
  • limit - Results per page (default 20)
  • query - Search by name, email, or phone
  • startAfter - Cursor for pagination (contact ID)
  • startAfterId - Cursor for pagination

Response:

{
  "contacts": [
    {
      "id": "abc123",
      "locationId": "loc123",
      "firstName": "John",
      "lastName": "Doe",
      "email": "john@example.com",
      "phone": "+15551234567",
      "companyName": "Acme Inc",
      "tags": ["customer", "vip"],
      "type": "lead",
      "dnd": false,
      "dateAdded": "2026-04-28T07:34:32.829Z",
      "customFields": []
    }
  ],
  "meta": {
    "total": 150,
    "startAfter": "abc123",
    "startAfterId": "abc123"
  }
}

Get Contact

GET /highlevel-pit/contacts/{contactId}

Response:

{
  "contact": {
    "id": "abc123",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com",
    "phone": "+15551234567",
    "tags": ["customer"],
    "type": "lead",
    "companyName": "Acme Inc",
    "customFields": [],
    "additionalEmails": [],
    "additionalPhones": []
  }
}

Create Contact

POST /highlevel-pit/contacts/
Content-Type: application/json

{
  "locationId": "{locationId}",
  "firstName": "John",
  "lastName": "Doe",
  "email": "john@example.com",
  "phone": "+15551234567",
  "companyName": "Acme Inc",
  "tags": ["customer"]
}

Update Contact

PUT /highlevel-pit/contacts/{contactId}
Content-Type: application/json

{
  "firstName": "Jane",
  "companyName": "New Company"
}

Delete Contact

DELETE /highlevel-pit/contacts/{contactId}

Search Contacts by Email/Phone

GET /highlevel-pit/contacts/?locationId={locationId}&query=john@example.com

Contact Tags

Add Tags

POST /highlevel-pit/contacts/{contactId}/tags
Content-Type: application/json

{
  "tags": ["vip", "priority"]
}

Response:

{
  "tags": ["customer", "vip", "priority"],
  "tagsAdded": ["vip", "priority"]
}

Remove Tags

DELETE /highlevel-pit/contacts/{contactId}/tags
Content-Type: application/json

{
  "tags": ["vip"]
}

Response:

{
  "tags": ["customer", "priority"],
  "tagsRemoved": ["vip"]
}

Contact Notes

List Notes

GET /highlevel-pit/contacts/{contactId}/notes

Create Note

POST /highlevel-pit/contacts/{contactId}/notes
Content-Type: application/json

{
  "body": "Spoke with client about renewal"
}

Response:

{
  "note": {
    "id": "note123",
    "body": "Spoke with client about renewal",
    "dateAdded": "2026-04-30T10:22:47.934Z",
    "contactId": "abc123"
  }
}

Update Note

PUT /highlevel-pit/contacts/{contactId}/notes/{noteId}
Content-Type: application/json

{
  "body": "Updated note content"
}

Delete Note

DELETE /highlevel-pit/contacts/{contactId}/notes/{noteId}

Contact Tasks

List Tasks

GET /highlevel-pit/contacts/{contactId}/tasks

Create Task

IMPORTANT: The completed field is required.

POST /highlevel-pit/contacts/{contactId}/tasks
Content-Type: application/json

{
  "title": "Follow up call",
  "body": "Discuss contract renewal",
  "dueDate": "2026-06-01T10:00:00Z",
  "completed": false
}

Response:

{
  "task": {
    "id": "task123",
    "title": "Follow up call",
    "body": "Discuss contract renewal",
    "dueDate": "2026-06-01T10:00:00.000Z",
    "completed": false,
    "contactId": "abc123"
  }
}

Update Task

PUT /highlevel-pit/contacts/{contactId}/tasks/{taskId}
Content-Type: application/json

{
  "title": "Updated task",
  "completed": true
}

Delete Task

DELETE /highlevel-pit/contacts/{contactId}/tasks/{taskId}

Opportunities (Deals)

Search Opportunities

GET /highlevel-pit/opportunities/search?location_id={locationId}

Query parameters:

  • location_id (required)
  • pipeline_id - Filter by pipeline
  • pipeline_stage_id - Filter by stage
  • status - open, won, lost, abandoned, all
  • contact_id - Filter by contact
  • q - Search query
  • limit - Results per page
  • page - Page number

Response:

{
  "opportunities": [
    {
      "id": "opp123",
      "name": "Enterprise Deal",
      "monetaryValue": 50000,
      "pipelineId": "pipe123",
      "pipelineStageId": "stage123",
      "status": "open",
      "contactId": "abc123",
      "contact": {
        "id": "abc123",
        "name": "John Doe",
        "email": "john@example.com"
      }
    }
  ],
  "meta": {
    "total": 25,
    "currentPage": 1,
    "nextPage": 2,
    "prevPage": null
  }
}

Get Opportunity

GET /highlevel-pit/opportunities/{opportunityId}

Create Opportunity

POST /highlevel-pit/opportunities/
Content-Type: application/json

{
  "pipelineId": "{pipelineId}",
  "locationId": "{locationId}",
  "name": "Enterprise Deal",
  "pipelineStageId": "{stageId}",
  "status": "open",
  "contactId": "{contactId}",
  "monetaryValue": 50000
}

Update Opportunity

IMPORTANT: pipelineId is required even when not changing it.

PUT /highlevel-pit/opportunities/{opportunityId}
Content-Type: application/json

{
  "pipelineId": "{pipelineId}",
  "name": "Updated Deal",
  "monetaryValue": 75000,
  "status": "won"
}

Delete Opportunity

DELETE /highlevel-pit/opportunities/{opportunityId}

Pipelines

List Pipelines

GET /highlevel-pit/opportunities/pipelines?locationId={locationId}

Response:

{
  "pipelines": [
    {
      "id": "pipe123",
      "name": "Sales Pipeline",
      "stages": [
        {
          "id": "stage-uuid",
          "name": "New Lead",
          "position": 0,
          "stageWinProbability": 14.29
        },
        {
          "id": "stage-uuid-2",
          "name": "Contacted",
          "position": 1,
          "stageWinProbability": 28.57
        }
      ]
    }
  ]
}

Calendars

List Calendars

GET /highlevel-pit/calendars/?locationId={locationId}

Response:

{
  "calendars": [
    {
      "id": "cal123",
      "locationId": "loc123",
      "name": "Personal Calendar",
      "calendarType": "personal",
      "eventType": "RoundRobin_OptimizeForAvailability",
      "slotDuration": 30,
      "teamMembers": [
        {
          "userId": "user123",
          "selected": true,
          "priority": 0.5
        }
      ]
    }
  ]
}

Get Calendar

GET /highlevel-pit/calendars/{calendarId}

Create Calendar

POST /highlevel-pit/calendars/
Content-Type: application/json

{
  "locationId": "{locationId}",
  "name": "Team Calendar",
  "calendarType": "personal",
  "eventType": "RoundRobin_OptimizeForAvailability",
  "teamMembers": [
    {
      "userId": "{userId}",
      "priority": 0.5,
      "selected": true
    }
  ]
}

Update Calendar

Note: Do NOT include locationId in the update body.

PUT /highlevel-pit/calendars/{calendarId}
Content-Type: application/json

{
  "name": "Updated Calendar",
  "calendarType": "personal",
  "eventType": "RoundRobin_OptimizeForAvailability",
  "teamMembers": [
    {
      "userId": "{userId}",
      "priority": 0.5,
      "selected": true
    }
  ]
}

Delete Calendar

DELETE /highlevel-pit/calendars/{calendarId}

Get Calendar Events

Requires at least one of calendarId, userId, or groupId.

GET /highlevel-pit/calendars/events?locationId={locationId}&calendarId={calendarId}&startTime={epochMs}&endTime={epochMs}

Query parameters:

  • locationId (required)
  • calendarId, userId, or groupId (at least one required)
  • startTime - Start of range (epoch milliseconds)
  • endTime - End of range (epoch milliseconds)

Get Free Slots

GET /highlevel-pit/calendars/{calendarId}/free-slots?startDate={epochMs}&endDate={epochMs}&timezone={timezone}

Calendar Groups

GET /highlevel-pit/calendars/groups?locationId={locationId}

Conversations

Search Conversations

GET /highlevel-pit/conversations/search?locationId={locationId}

Query parameters:

  • locationId (required)
  • limit - Results per page
  • contactId - Filter by contact
  • assignedTo - Filter by assigned user
  • status - Filter by status

Response:

{
  "conversations": [
    {
      "id": "conv123",
      "locationId": "loc123",
      "contactId": "abc123",
      "fullName": "John Doe",
      "type": "TYPE_PHONE",
      "lastMessageDate": 1777361673411,
      "lastMessageType": "TYPE_NO_SHOW",
      "unreadCount": 0
    }
  ],
  "total": 5
}

Get Conversation

GET /highlevel-pit/conversations/{conversationId}

Get Conversation Messages

GET /highlevel-pit/conversations/{conversationId}/messages

Create Conversation

POST /highlevel-pit/conversations/
Content-Type: application/json

{
  "locationId": "{locationId}",
  "contactId": "{contactId}"
}

Users

List Users

GET /highlevel-pit/users/?locationId={locationId}

Response:

{
  "users": [
    {
      "id": "user123",
      "name": "Admin User",
      "firstName": "Admin",
      "lastName": "User",
      "email": "admin@example.com",
      "phone": "+15551234567",
      "roles": {
        "type": "admin",
        "role": "admin",
        "locationIds": ["loc123"]
      }
    }
  ]
}

Location Tags

List Tags

GET /highlevel-pit/locations/{locationId}/tags

Response:

{
  "tags": [
    {
      "id": "tag123",
      "name": "VIP Customer",
      "locationId": "loc123"
    }
  ]
}

Create Tag

POST /highlevel-pit/locations/{locationId}/tags
Content-Type: application/json

{
  "name": "New Tag"
}

Get Tag

GET /highlevel-pit/locations/{locationId}/tags/{tagId}

Update Tag

PUT /highlevel-pit/locations/{locationId}/tags/{tagId}
Content-Type: application/json

{
  "name": "Updated Tag"
}

Delete Tag

DELETE /highlevel-pit/locations/{locationId}/tags/{tagId}

Custom Fields

List Custom Fields

GET /highlevel-pit/locations/{locationId}/customFields

Response:

{
  "customFields": [
    {
      "id": "cf123",
      "name": "Customer ID",
      "fieldKey": "contact.customer_id",
      "dataType": "TEXT",
      "model": "contact",
      "position": 50
    }
  ]
}

Create Custom Field

POST /highlevel-pit/locations/{locationId}/customFields
Content-Type: application/json

{
  "name": "Customer ID",
  "dataType": "TEXT",
  "model": "contact"
}

Valid dataType values: TEXT, LARGE_TEXT, NUMERICAL, PHONE, MONETORY, CHECKBOX, SINGLE_OPTIONS, MULTIPLE_OPTIONS, FLOAT, DATE, TEXTBOX_LIST, FILE_UPLOAD, SIGNATURE

Valid model values: contact, opportunity

Get Custom Field

GET /highlevel-pit/locations/{locationId}/customFields/{customFieldId}

Update Custom Field

PUT /highlevel-pit/locations/{locationId}/customFields/{customFieldId}
Content-Type: application/json

{
  "name": "Updated Field Name"
}

Delete Custom Field

DELETE /highlevel-pit/locations/{locationId}/customFields/{customFieldId}

Custom Values

List Custom Values

GET /highlevel-pit/locations/{locationId}/customValues

Response:

{
  "customValues": [
    {
      "id": "cv123",
      "name": "Company Tagline",
      "fieldKey": "{{ custom_values.company_tagline }}",
      "value": "We build great things",
      "locationId": "loc123"
    }
  ]
}

Create Custom Value

POST /highlevel-pit/locations/{locationId}/customValues
Content-Type: application/json

{
  "name": "Company Tagline",
  "value": "We build great things"
}

Get Custom Value

GET /highlevel-pit/locations/{locationId}/customValues/{customValueId}

Update Custom Value

PUT /highlevel-pit/locations/{locationId}/customValues/{customValueId}
Content-Type: application/json

{
  "name": "Updated Name",
  "value": "Updated value"
}

Delete Custom Value

DELETE /highlevel-pit/locations/{locationId}/customValues/{customValueId}

Businesses

List Businesses

GET /highlevel-pit/businesses/?locationId={locationId}

Response:

{
  "success": true,
  "businesses": [
    {
      "id": "biz123",
      "name": "Acme Inc",
      "locationId": "loc123",
      "city": "Los Angeles",
      "website": "www.acme.com",
      "phone": "+15551234567",
      "email": "info@acme.com"
    }
  ]
}

Get Business

GET /highlevel-pit/businesses/{businessId}

Create Business

POST /highlevel-pit/businesses/
Content-Type: application/json

{
  "locationId": "{locationId}",
  "name": "New Business",
  "city": "San Francisco",
  "phone": "+15551234567",
  "email": "info@newbiz.com",
  "website": "www.newbiz.com"
}

Update Business

PUT /highlevel-pit/businesses/{businessId}
Content-Type: application/json

{
  "name": "Updated Business",
  "city": "Los Angeles"
}

Delete Business

DELETE /highlevel-pit/businesses/{businessId}

Products

List Products

GET /highlevel-pit/products/?locationId={locationId}

Get Product

GET /highlevel-pit/products/{productId}?locationId={locationId}

Note: locationId query parameter is required even for single product retrieval.

Create Product

POST /highlevel-pit/products/
Content-Type: application/json

{
  "locationId": "{locationId}",
  "name": "Digital Course",
  "description": "Online training program",
  "productType": "DIGITAL"
}

Delete Product

DELETE /highlevel-pit/products/{productId}?locationId={locationId}

Invoices

List Invoices

IMPORTANT: Both offset and altId/altType are required.

GET /highlevel-pit/invoices/?altId={locationId}&altType=location&limit=20&offset=0

Get Invoice

GET /highlevel-pit/invoices/{invoiceId}?altId={locationId}&altType=location

Payments

List Orders

GET /highlevel-pit/payments/orders?altId={locationId}&altType=location&limit=20

List Transactions

GET /highlevel-pit/payments/transactions?altId={locationId}&altType=location&limit=20

List Subscriptions

GET /highlevel-pit/payments/subscriptions?altId={locationId}&altType=location&limit=20

Trigger Links

List Links

GET /highlevel-pit/links/?locationId={locationId}

Create Link

POST /highlevel-pit/links/
Content-Type: application/json

{
  "locationId": "{locationId}",
  "name": "Survey Link",
  "redirectTo": "https://example.com/survey"
}

Response:

{
  "link": {
    "id": "link123",
    "name": "Survey Link",
    "redirectTo": "https://example.com/survey",
    "fieldKey": "{{trigger_link.link123}}"
  }
}

Update Link

PUT /highlevel-pit/links/{linkId}
Content-Type: application/json

{
  "name": "Updated Link",
  "redirectTo": "https://updated.com"
}

Delete Link

DELETE /highlevel-pit/links/{linkId}

Workflows

List Workflows

GET /highlevel-pit/workflows/?locationId={locationId}

Campaigns

List Campaigns

GET /highlevel-pit/campaigns/?locationId={locationId}

Forms

List Forms

GET /highlevel-pit/forms/?locationId={locationId}

Surveys

List Surveys

GET /highlevel-pit/surveys/?locationId={locationId}

Funnels

List Funnels

GET /highlevel-pit/funnels/funnel/list?locationId={locationId}

Response:

{
  "funnels": [...],
  "count": 5
}

Social Media

List Accounts

GET /highlevel-pit/social-media-posting/{locationId}/accounts

Response:

{
  "success": true,
  "results": {
    "accounts": [...],
    "groups": [...]
  }
}

List Categories

GET /highlevel-pit/social-media-posting/{locationId}/categories

Media Files

List Files

IMPORTANT: The type parameter is required.

GET /highlevel-pit/medias/files?altId={locationId}&altType=location&type=file&limit=20

Valid type values: file, image, video, audio

Pagination

GoHighLevel uses different pagination styles depending on the endpoint:

Cursor-Based (Contacts)

GET /highlevel-pit/contacts/?locationId={locationId}&limit=20&startAfterId={lastContactId}

Response includes meta.startAfterId for the next page cursor.

Offset-Based (Opportunities, Invoices)

GET /highlevel-pit/opportunities/search?location_id={locationId}&limit=20&page=2
GET /highlevel-pit/invoices/?altId={locationId}&altType=location&limit=20&offset=20

Skip-Based (Locations)

GET /highlevel-pit/locations/search?companyId={companyId}&limit=20&skip=20

Code Examples

JavaScript

const response = await fetch(
  'https://api.maton.ai/highlevel-pit/contacts/?locationId={locationId}&limit=20',
  {
    headers: {
      'Authorization': `Bearer ${process.env.MATON_API_KEY}`,
      'Maton-Connection': '{sub-account-connection-id}'
    }
  }
);
const data = await response.json();

Python

import os
import requests

response = requests.get(
    'https://api.maton.ai/highlevel-pit/contacts/',
    headers={
        'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
        'Maton-Connection': '{sub-account-connection-id}'
    },
    params={'locationId': '{locationId}', 'limit': 20}
)
data = response.json()

Notes

  • Two token types: Agency tokens manage locations; Sub-Account tokens access CRM data within a location. Use the Maton-Connection header to pick the right one.
  • Most Sub-Account endpoints require a locationId query parameter
  • Payment/invoice endpoints use altId and altType=location instead of locationId
  • Social media endpoints put locationId in the URL path, not as a query param
  • Calendar events require startTime/endTime as epoch milliseconds, not ISO-8601
  • Calendar event queries require at least one of calendarId, userId, or groupId
  • Calendar update does NOT accept locationId in the body (returns 422)
  • Product GET requires locationId as a query parameter
  • Contact task creation requires the completed field (boolean)
  • Opportunity update requires pipelineId even when not changing it
  • Invoice list requires offset parameter (use 0 for first page)
  • Media file list requires the type parameter
  • All delete operations return HTTP 200 (not 204)
  • IMPORTANT: When using curl commands, use curl -g when URLs contain brackets to disable glob parsing
  • IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments

Error Handling

StatusMeaning
400Bad request or invalid parameters
401Invalid/missing Maton API key, token not authorized for scope, or user type mismatch
403Token does not have access to this location
404Resource not found
422Validation error — check required fields
429Rate limited
4xx/5xxPassthrough error from GoHighLevel API

Common Errors

"The token does not have access to this location" (403): You're using an Agency token for an endpoint that requires a Sub-Account token, or vice versa.

"The token is not authorized for this scope" (401): The token doesn't have the required scope. Agency tokens can't access CRM data; Sub-Account tokens can't manage locations.

"Token's user type mismatch" (401): You're using the wrong token type for this endpoint (e.g., Agency token on a Sub-Account-only endpoint).

"LocationId can't be undefined" (422): You forgot the locationId query parameter.

Resources

Version tags

latestvk9709hdgx43vptf3mz351ex7f185x7ez

Runtime requirements

🧠 Clawdis
EnvMATON_API_KEY