🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

GoHighLevel

by @byungkyu

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

TERMINAL
clawhub install highlevel-api

πŸ“– About This Skill


name: highlevel-pit description: | GoHighLevel (Private Integration Token) API integration with managed auth. CRM, sales pipelines, calendars, conversations, payments, and marketing automation. Use this skill when users want to manage contacts, opportunities, calendars, conversations, invoices, products, or workflows in GoHighLevel using a Private Integration Token (PIT). GoHighLevel has two token types: Agency tokens and Sub-Account tokens. Agency tokens manage locations (sub-accounts), while Sub-Account tokens access CRM, calendars, pipelines, and other location-scoped data. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Requires network access and valid Maton API key. metadata: author: maton version: "1.0" clawdbot: emoji: 🧠 requires: env: - MATON_API_KEY

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 Type | Purpose | Key Capabilities | |---|---|---| | Agency | Manage the agency and its sub-accounts (locations) | Search/create/update/delete locations, manage snapshots | | Sub-Account | Operate within a specific location | Contacts, 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

    | Status | Meaning | |--------|---------| | 400 | Bad request or invalid parameters | | 401 | Invalid/missing Maton API key, token not authorized for scope, or user type mismatch | | 403 | Token does not have access to this location | | 404 | Resource not found | | 422 | Validation error β€” check required fields | | 429 | Rate limited | | 4xx/5xx | Passthrough 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

  • GoHighLevel API Documentation
  • GoHighLevel Marketplace
  • Private Integration Token Guide
  • Maton Community
  • Maton Support
  • πŸ’‘ Examples

    # 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"
    

    πŸ“‹ Tips & Best Practices

  • 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