> ## Documentation Index
> Fetch the complete documentation index at: /help/llms.txt
> Use this file to discover all available pages before exploring further.

# HighLevel

> Upsert HighLevel contacts when LinkedIn contacts reply, send HighLevel contacts into Kerux campaigns, and stop follow-ups when an appointment is booked.

> [!NOTE]
>
> **Pro plan.** HighLevel works through a trigger URL, a connection, HTTP steps and a booking tool, which are part of Pro and Agency (and the free trial). Anything you already have keeps working on every plan. See [Plans and billing](/help/account/billing.md).

Three things you can set up, alone or together:

* **Kerux to HighLevel:** when a contact replies, a **Webhook / HTTP** step creates or updates the contact and adds a tag that starts your HighLevel workflow.
* **HighLevel to Kerux:** a HighLevel workflow sends contacts into a Kerux campaign with its **Custom Webhook** action.
* **Bookings:** an **Appointment Booked** workflow tells Kerux, which stops the LinkedIn follow-ups.

> [!NOTE]
>
> **How it connects:** HighLevel's API v2 with a Private Integration token, and its workflow Custom Webhook action. See HighLevel's [Upsert Contact](https://marketplace.gohighlevel.com/docs/ghl/contacts/upsert-contact), [Private Integrations](https://marketplace.gohighlevel.com/docs/Authorization/PrivateIntegrationsToken/) and [Custom Webhook](https://help.gohighlevel.com/support/solutions/articles/155000003305-workflow-action-custom-webhook) docs. Requests and answers follow HighLevel's docs.

## Before you start

* **A Private Integration token** for the sub-account (location): in HighLevel, open **Settings > Private Integrations**, create one with the contacts scopes and copy the token. HighLevel allows up to 20 per sub-account.
* **The location id** of the sub-account (in its settings or address bar).

## 1. Connect HighLevel

In Kerux, open **Integrations > Connections**, click **Connect** on **Custom API** (under **Developers**):

* **How it signs in:** **Bearer token**, paste the token.
* **Base URL:** `https://services.leadconnectorhq.com`

Click **Save**. One connection per client sub-account.

## 2. Upsert the contact when a contact replies

A contact who replies leaves the campaign (the **When the contact replies** box). In that box, add **Send to another campaign** and pick a short "Replied: to HighLevel" campaign. Its first step is a **Webhook / HTTP** step with the HighLevel connection:

```json theme={null}
{
  "method": "POST",
  "url": "/contacts/upsert",
  "headers": { "Version": "2021-07-28" },
  "bodyType": "json",
  "body": {
    "locationId": "YOUR_LOCATION_ID",
    "firstName": "{{contact.first_name}}",
    "lastName": "{{contact.last_name | optional}}",
    "email": "{{email}}",
    "tags": ["linkedin-replied"],
    "source": "Kerux"
  }
}
```

The `Version` header is required by HighLevel's API v2; use the value shown on the endpoint's page in HighLevel's docs. Upsert follows your sub-account's **Allow Duplicate Contact** setting to decide whether to update an existing contact (by email, phone or both).

HighLevel answers (from its docs): `{ "new": true, "contact": { "id": "...", ... } }`. The id is `{{steps.<step>.response.body.contact.id}}`.

In HighLevel, start a workflow with the trigger **Contact Tag** added `linkedin-replied`.

## 3. Send HighLevel contacts into a Kerux campaign

In a HighLevel workflow, add the **Custom Webhook** action:

* **Method:** POST, **URL:** the campaign's trigger URL (in Kerux: open the campaign, **+ Add** on the **Trigger** half of the start box, **Incoming webhook (API)**, **Add**, **Copy link**).
* **Body:** JSON with Kerux's field names and HighLevel's merge fields as values. `linkedin_url` is required, so keep the LinkedIn profile in a contact custom field.

```json theme={null}
{
  "linkedin_url": "CONTACT_LINKEDIN_CUSTOM_FIELD",
  "first_name": "CONTACT_FIRST_NAME",
  "email": "CONTACT_EMAIL"
}
```

Replace the capitals with HighLevel's merge fields from the action's picker.

## 4. Stop follow-ups when an appointment is booked

In Kerux, click **Meetings**, go to **Booking tools**, pick **Another booking tool** and click **Add a booking tool**, then **Manage** and **Copy URL**. In HighLevel, add a workflow with the **Appointment Booked** trigger (or **Appointment Status**) and a **Custom Webhook** action that POSTs to that URL with:

```json theme={null}
{
  "event": "meeting.booked",
  "id": "APPOINTMENT_ID",
  "email": "CONTACT_EMAIL",
  "name": "CONTACT_FULL_NAME",
  "title": "APPOINTMENT_TITLE",
  "start": "APPOINTMENT_START_ISO",
  "end": "APPOINTMENT_END_ISO",
  "link": "MEETING_LINK"
}
```

Send `start` and `end` as full dates with a time zone. Kerux finds the contact by email. For cancellations, a second workflow sends `"event": "meeting.cancelled"` with the same `id`.

## Test with one contact

In the follow-up campaign's **Builder**, click **Test** to open **Test on one contact**; check the contact and its tag in HighLevel. Book a test appointment with a contact's email and check the booking tool's row says **Receiving**.

## Common errors

> [accordion] 401 from HighLevel
>
> The token is wrong or for another sub-account, or the `Version` header is missing.

> [accordion] 403 with a scope message
>
> The Private Integration doesn't have the contacts scope. Edit it in HighLevel (the token stays the same).

> [accordion] The booking doesn't stop the contact
>
> The email in the webhook doesn't match the contact's email in Kerux, or `event` isn't `meeting.booked`. The booking tool's row shows the last delivery.

Related: [Meetings booked by contacts](/help/campaigns/meetings.md), [Trigger URLs and forms](/help/developers/trigger-urls-and-forms.md), [Webhook steps](/help/integrations/webhook-steps.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.