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

# GoHighLevel integration guide

> Connect HighLevel, map CRM data, and configure events and goals to measure pipeline and revenue outcomes.

Stiddle connects GoHighLevel CRM data with customer identity, website activity, marketing touchpoints and spend. Connect using OAuth or a Private Integration token, sync contacts, customer companies and opportunities, then create events and goals to measure progress from first touch through pipeline and revenue.

This guide covers connection, permissions, field mapping, identity relationships, CRM events, pipeline goals, attribution reporting and troubleshooting. The managed connector suits most deployments; the API, webhook, CSV and warehouse routes serve custom setups. Choose one authoritative ingestion route per dataset.

GoHighLevel is referred to as **HighLevel** throughout. In Stiddle, opportunities appear as **Deals** and customer companies as **Companies** or **CRM Accounts**.

## Before you begin

Most deployments follow the standard path below:

1. Plan the scope: the HighLevel sub-account, pipelines, conversion rules and owners.
2. Connect HighLevel with OAuth or a Private Integration token.
3. Map contact, company and opportunity fields into Stiddle properties.
4. Define CRM events and the goals that count them.
5. Measure attribution, pipeline value and acquisition costs.
6. Validate the connection end to end before relying on reports.

If your HighLevel data already passes through middleware, a warehouse or file exports, an alternative ingestion route replaces step 2.

## In this guide

* [Connection methods and data flow](#connection-methods-and-data-flow)
* [Requirements and HighLevel permissions](#requirements-and-highlevel-permissions)
* [Connect with OAuth](#connect-with-oauth)
* [Connect with a Private Integration token](#connect-with-a-private-integration-token)
* [Configure the sync and record relationships](#configure-the-sync-and-record-relationships)
* [Data schema and field mapping](#data-schema-and-field-mapping)
* [CRM events](#crm-events)
* [Pipeline and revenue goals](#pipeline-and-revenue-goals)
* [Attribution and acquisition costs](#attribution-and-acquisition-costs)
* [Alternative ingestion routes and sync back to HighLevel](#alternative-ingestion-routes-and-sync-back-to-highlevel)
* [Validation and troubleshooting](#validation-and-troubleshooting)

## Connection methods and data flow

The connection brings all authorized contacts, customer companies and opportunities within the selected HighLevel sub-account into Stiddle. Pipelines and stages provide the context needed to interpret opportunity changes. The selected sub-account, credentials and any filters you apply define the records in scope.

![Diagram of HighLevel records syncing into Stiddle, joining the identity graph, and becoming events, goals and reports](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/18-data-flow.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=9b029eaf2531c4688a3b1e2101d64608)

| Step | What happens | What you use it for |
| - | - | - |
| Connect | Authorize HighLevel with OAuth or a Private Integration token | Give Stiddle access to the intended sub-account |
| Sync records | Import contacts, customer companies, opportunities and pipeline definitions | Populate People Profiles, Companies and Deals |
| Resolve identity | Associate CRM contacts with individuals in Stiddle's identity graph | Connect website and marketing touchpoints to CRM outcomes |
| Link records | Associate the individual with the relevant company and opportunity | Understand account journeys and pipeline progression |
| Define events | Select a source and a meaningful record action or stage transition | Track individual business touchpoints |
| Define goals | Choose the events that represent outcomes and optionally assign value | Measure conversions, pipeline value, revenue and acquisition costs |

A synced record stores the current CRM state. An event describes something that happened. A goal defines which events count toward an outcome. For example, syncing an opportunity that is currently in Qualified doesn't tell Stiddle when it entered Qualified, and doesn't count as a new conversion today.

![Diagram comparing a synced record, an event and a goal](https://mintcdn.com/stiddle/z_SaLYTbL7bpbXj8/images/gohighlevel/19-record-event-goal.png?fit=max\&auto=format\&n=z_SaLYTbL7bpbXj8\&q=85\&s=c858378d7e0d333863b336f814de1088)

### Choose an authentication method

| Method | Use when | Ongoing access |
| - | - | - |
| OAuth (recommended) | You want the standard authorization flow with automatic change notifications | Stiddle manages the connection and token refresh |
| Private Integration token | You need a credential-based connection to one sub-account | You maintain the token and update Stiddle when you rotate it |

Both methods feed the same records, identity, events and goals in Stiddle. OAuth connections receive HighLevel change notifications through the Marketplace app. Private Integration tokens don't create Marketplace webhook subscriptions, so token connections refresh on a schedule instead.

See HighLevel's [authorization documentation](https://marketplace.gohighlevel.com/docs/Authorization/authorization_doc/).

## Requirements and HighLevel permissions

A Stiddle workspace administrator configures the connection, properties, events and goals. A HighLevel administrator grants access to the intended sub-account. Your marketing or RevOps owner should agree pipeline definitions, conversion rules, value definitions and reporting currency before you enable goals.

### Required information

* The Stiddle workspace that should receive the data.
* The HighLevel sub-account name and location ID, plus the responsible administrator.
* OAuth installation access, or a Private Integration token scoped to that sub-account.
* The pipelines, stage IDs and stage names used for qualification, sales progression and customer acquisition.
* A list of the fields you need for identity, company relationships, opportunity value and custom fields.
* The historical period, time zone and reporting currency, plus the person who will monitor the sync.

### Permission matrix

Connect at the sub-account level. An agency authorization doesn't mean every agency sub-account should be imported into one Stiddle workspace.

| HighLevel scope | Purpose | When needed |
| - | - | - |
| `contacts.readonly` | Read contacts and business-linked contacts | Core contact sync |
| `businesses.readonly` | Read customer business/company records | Core company sync |
| `opportunities.readonly` | Read opportunities and pipelines | Core opportunity and stage sync |
| `locations.readonly` | Read sub-account identity and settings | Validate location context |
| `locations/customFields.readonly` | Read field definitions | Discover and map custom fields |
| `users.readonly` | Resolve assigned users | Optional owner enrichment |
| `associations/relation.readonly` | Read supported record relations | Only when using record relations |

Inbound sync only needs read access. Write scopes are required only if you set up [sync back to HighLevel](#sync-back-to-highlevel).

See HighLevel's [scope reference](https://marketplace.gohighlevel.com/docs/Authorization/Scopes/).

### Companies and sub-accounts

HighLevel uses several organization concepts:

| HighLevel concept | What it is | How Stiddle uses it |
| - | - | - |
| Agency company | The agency account that manages sub-accounts | Not imported as a customer company |
| Location (sub-account) | The CRM workspace containing contacts and opportunities | The connection scope; one location per Stiddle workspace |
| Business | A customer company inside a location | Imported as a Stiddle Company / CRM Account |

![Diagram of an agency account containing sub-accounts, each routed to its own Stiddle workspace](https://mintcdn.com/stiddle/z_SaLYTbL7bpbXj8/images/gohighlevel/20-highlevel-accounts.png?fit=max\&auto=format\&n=z_SaLYTbL7bpbXj8\&q=85\&s=629233e5e01a45f23523afce6889943c)

An agency company ID, location ID and customer business ID are different identifiers. Stiddle stores the record type with each ID so they never collide.

See HighLevel's [customer business reference](https://marketplace.gohighlevel.com/docs/ghl/businesses/get-businesses-by-location/).

## Connect with OAuth

OAuth is the recommended method. You authorize Stiddle in HighLevel without sharing a password or client secret.

1. Open the correct Stiddle workspace and go to **Data → Connectors**.
2. Select **Sales Channels**, find **HighLevel**, and choose **Connect To Stiddle**. For an existing connection, choose **Configure**.
3. Choose **Connect with OAuth**.
4. Sign in to HighLevel if prompted and select the intended sub-account. If you are installing from an agency account, select only the locations that should connect to this workspace.
5. Review the Stiddle app and requested permissions, then approve the connection.
6. Return to Stiddle and confirm the connected location name and ID.
7. Review the datasets and mappings, then start the initial sync.

![HighLevel OAuth connection screen in Stiddle](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/01-oauth-connect.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=cb21af00cb3e0c2f85395306b9844559)

### What Stiddle manages

For OAuth connections, Stiddle handles authorization, access tokens and token refresh. If authorization is removed or permissions change, reconnect using a HighLevel administrator who can approve the required scopes.

To connect another location, route it to its own workspace. Each imported record keeps its location ID, and agency clients aren't combined just because their contacts share an email domain.

See HighLevel's [OAuth reference](https://marketplace.gohighlevel.com/docs/Authorization/OAuth2.0/).

## Connect with a Private Integration token

The **Use API key / token** option takes a HighLevel **Private Integration token**. HighLevel's legacy API keys belong to its older API and don't work with this connection.

### Create and connect a token

1. In HighLevel, open the settings for the sub-account and go to **Private Integrations**. An administrator may need to enable this feature.
2. Create a new integration named **Stiddle CRM Sync**.
3. Select only the read scopes listed in the [permission matrix](#permission-matrix).
4. Copy the generated token and store it securely.
5. In Stiddle, open **Data → Connectors → HighLevel** and choose **Use API key / token**.
6. Enter the **Location ID** and paste the **Private Integration token**.
7. Connect, then confirm the location name and the first sync result.

![Private Integration token connection form in Stiddle](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/02-token-connect.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=16500bbbb7fba58131f6850aff46767a)

### Maintain the token

Treat the token as a secret. Keep it out of CSV files, screenshots, event properties and reports. When you rotate it in HighLevel, update it in Stiddle, test the connection and confirm syncing resumes in **Sync Logs** before retiring the old token.

See HighLevel's [Private Integration reference](https://marketplace.gohighlevel.com/docs/Authorization/PrivateIntegrationsToken/).

## Configure the sync and record relationships

After authorization, Stiddle syncs contacts, customer companies, opportunities, and pipeline and stage definitions for the selected location. Opportunities in every status are included: open, won, lost and abandoned.

![Connected HighLevel account with configuration controls](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/03-connected-account.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=89b5d9355244611f0a4646226221a34c)

The connection settings include:

| Control | Use |
| - | - |
| Add Custom Objects | Define property-based conversion rules and conversion values |
| Add Sync Parameters | Map HighLevel properties into Stiddle properties |
| Re-sync Data | Refresh existing records after changing mappings |
| Disconnect HighLevel | Remove the connection |

### Initial sync

During the initial sync, Stiddle:

1. Loads pipeline and stage definitions, plus selected custom-field definitions.
2. Imports customer businesses and contacts, and links contacts to their businesses.
3. Imports opportunities with their contact, pipeline and stage identifiers.
4. Links each opportunity to its contact, and to the relevant company where that relationship exists.

When it finishes, compare record counts between HighLevel and Stiddle using the same filters, and review any failed or skipped records in **Sync Logs** before enabling conversion reporting.

### How records are linked

Stiddle identifies each HighLevel record by **source + location ID + record type + record ID**. These IDs are kept even when several CRM records resolve to one Stiddle individual.

![Diagram of HighLevel record relationships and the compound record key](https://mintcdn.com/stiddle/z_SaLYTbL7bpbXj8/images/gohighlevel/21-record-relationships.png?fit=max\&auto=format\&n=z_SaLYTbL7bpbXj8\&q=85\&s=847995ee933a4e035a699bf8b87b287a)

| Relationship | Source key | Stiddle result |
| - | - | - |
| Contact to individual | Contact ID plus email and phone | A CRM contact associated with a person profile |
| Contact to customer company | Business relationship in HighLevel | Company membership for the person |
| Opportunity to contact | Opportunity `contactId` | Deal linked to its individual |
| Opportunity to company | The contact's business relationship | Deal linked to a customer account |
| Opportunity to stage | Location, pipeline ID and stage ID | Correct pipeline position and stage name |

Stiddle's identity graph connects CRM contacts with their identified website and marketing touchpoints. Importing contacts doesn't identify every past anonymous visit.

Email and normalized phone are used for matching. Shared mailboxes, shared phone numbers and duplicate CRM contacts can affect matching. Company names are display values, not relationship keys, so contacts are linked to companies only through explicit HighLevel relationships.

### Ongoing changes

After the initial sync, Stiddle keeps the same records up to date. OAuth connections receive HighLevel change notifications; token connections refresh on a schedule. Check **Sync Logs** to see the latest activity.

The initial sync imports each record's current state. It can't recreate stage history that HighLevel didn't keep, so opportunities already in a stage aren't counted as entering that stage on the day you connect. Stage-based goals count transitions that happen after the connection is live.

### Apply changes and re-sync

Use a re-sync to refresh existing records after you change mappings or need to recover a missed period.

1. Open **Data → Connectors → HighLevel → Configure**.
2. Choose **Re-sync Data**.
3. In **Configure Sync**, review the **HighLevel Properties → Stiddle Properties** mappings.
4. Add or adjust property rows as needed, or choose **Skip** to keep the current mappings.
5. Choose **Next** and review **Confirm Sync**.
6. Choose **Finish** to save and start the refresh.
7. Check **Sync Logs** and review a few contact, company and opportunity records.

![Configure Sync step showing HighLevel to Stiddle property mappings](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/04-configure-sync-mappings.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=ce2be04a9c514e51af2d4000f3855745)

![Confirm Sync dialog for HighLevel re-sync](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/05-confirm-resync.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=5e4d11e4b2516f13e4bf439943779b99)

The confirmation message means your settings were saved; the refresh runs in the background. A re-sync updates existing records and doesn't create new stage conversions for opportunities whose stage hasn't changed.

## Data schema and field mapping

Stiddle property groups organize data by connection and record type. Use the existing CRM groups or create your own. A group can hold many properties, and a property can belong to more than one group.

### Common HighLevel property groups

| Stiddle group | Group ID | Use |
| - | - | - |
| Contact Group | `contact_group` | General person fields such as first name and email |
| CRM Contact | `crm_contact` | HighLevel contact identifiers and CRM attributes |
| CRM Account | `crm_account` | Customer company/business data |
| CRM Opportunity | `crm_opportunity` | Opportunity, pipeline, stage, status and value |
| CRM Event | `crm_event` | Event context, source identifiers and event properties |

![Stiddle CRM property groups](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/06-property-groups.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=eb14d0a46615a00aa20afe5decae37fa)

### Mapping rules

Use the tables below as a starting point. The fields available depend on your HighLevel account, and the `ghl_` keys are suggested names you can change.

* Store IDs as strings.
* Store money as numbers, with currency kept in a separate property.
* Store timestamps as `DATETIME` in a consistent time zone.
* Map multi-value fields such as tags to a list property rather than a single text string.

### Contact properties

| HighLevel field | Suggested Stiddle property | Type |
| - | - | - |
| `id` | `ghl_contact_id` | STRING |
| `locationId` | `ghl_location_id` | STRING |
| `firstName` | `first_name` | STRING |
| `lastName` | `last_name` | STRING |
| `name` | `ghl_contact_name` | STRING |
| `email` | `email` | STRING |
| `phone` | `contact_number` | STRING |
| `companyName` | `ghl_company_name` | STRING |
| Business relationship | `ghl_business_id` | STRING |
| `assignedTo` | `ghl_assigned_to` | STRING |
| `source` | `ghl_contact_source` | STRING |
| `dateAdded` | `ghl_contact_created_at` | DATETIME |
| `dateUpdated` | `ghl_contact_updated_at` | DATETIME |
| `address1`, `city`, `state`, `postalCode`, `country` | Separate address properties | STRING per field |
| `dnd` | `ghl_dnd` | BOOLEAN |
| `tags` | `ghl_tags` | List |
| `customFields` | One property per selected custom field | Depends on field |

HighLevel's DND setting is a communication preference; it doesn't replace your website consent configuration. Only map additional personal fields when you have a defined use for them.

See HighLevel's [contacts reference](https://marketplace.gohighlevel.com/docs/ghl/contacts/contacts/).

### Company properties

HighLevel business records map to Stiddle Companies. Agency-level metadata is kept separate.

| HighLevel business field | Suggested Stiddle property | Type |
| - | - | - |
| `id` | `ghl_business_id` | STRING |
| `locationId` | `ghl_location_id` | STRING |
| `name` | `ghl_company_name` | STRING |
| `website` | `ghl_company_website` | STRING |
| `email` | `ghl_company_email` | STRING |
| `phone` | `ghl_company_phone` | STRING |
| `address`, `city`, `state`, `postalCode`, `country` | Separate company address properties | STRING per field |
| `description` | `ghl_company_description` | STRING |
| `createdAt` | `ghl_company_created_at` | DATETIME |
| `updatedAt` | `ghl_company_updated_at` | DATETIME |

Companies without linked contacts are still imported, and their relationships are completed when contacts are linked later.

### Opportunity properties

| HighLevel field | Suggested Stiddle property | Type |
| - | - | - |
| `id` | `ghl_opportunity_id` | STRING |
| `locationId` | `ghl_location_id` | STRING |
| `contactId` | `ghl_contact_id` | STRING |
| `name` | `ghl_opportunity_name` | STRING |
| `pipelineId` | `ghl_pipeline_id` | STRING |
| `pipelineStageId` | `ghl_pipeline_stage_id` | STRING |
| `status` | `ghl_status` | STRING |
| `monetaryValue` | `ghl_monetary_value` | NUMBER |
| `assignedTo` | `ghl_assigned_to` | STRING |
| `source` | `ghl_opportunity_source` | STRING |
| `dateAdded` | `ghl_opportunity_created_at` | DATETIME |
| Last updated time | `ghl_opportunity_updated_at` | DATETIME |
| Pipeline and stage names | `ghl_pipeline_name`, `ghl_stage_name` | STRING |
| Customer business (via contact) | `ghl_business_id` | STRING |
| Selected custom fields | One property per field | Depends on field |

Use `monetaryValue` as the source for **Opportunity Amount**, and store the reporting currency separately. Opportunity amount is pipeline value, not collected revenue.

See HighLevel's [opportunities reference](https://marketplace.gohighlevel.com/docs/ghl/opportunities/opportunities/).

### Configure inbound property mappings

1. Open the HighLevel connection and choose **Add Sync Parameters**.
2. Under **HighLevel Properties**, select the source field. For opportunity value, select `monetaryValue`.
3. Under **Stiddle Properties**, select the destination, such as **Opportunity Amount**.
4. Choose **Add** for each additional mapping, review the rows, then choose **Save**.
5. Refresh a test record and confirm the stored value in Stiddle.

![Mapping HighLevel opportunity amount to a Stiddle property](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/07-map-opportunity-amount.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=62e89f4bfa19306eb33f82a9050f3989)

![Searching HighLevel source properties by record type](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/08-search-source-properties.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=a5e6741bd4261833cf80ec5211b92487)

![Choosing the destination Stiddle property](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/09-choose-destination-property.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=0b7ea46d4d60210bfdbf52fb5d5ac890)

A field's label in HighLevel may differ from its API key, so note both when you plan mappings. The destination property should have the same meaning and a compatible type.

### Create custom properties

1. Review the location's custom fields and choose the ones you need for reporting.
2. Match fields by their ID or key and record type, not only their display name.
3. Create a Stiddle property with the correct type if no suitable one exists.
4. Add the property to the relevant groups, including **CRM Event** if you need it as event context.
5. Map sample values and check empty, number, date, dropdown and multi-value fields.
6. Update the field in HighLevel and confirm the change reaches Stiddle.

Give each property one clear meaning. For example, contact name and opportunity name shouldn't share a property just because both HighLevel fields are called `name`.

## CRM events

An event in Stiddle starts with a source, such as a CRM connection, webhook, API or import. You then choose the action or transition that represents the touchpoint.

Useful HighLevel events include contact created, company created, opportunity created, entry into a pipeline stage, and opportunity status changes. The connector syncs the records; **Events Manager** defines the business events you want to analyze. If your workspace includes default HighLevel events, review their rules before using them in goals.

### Set conversion rules and values

**Add Custom Objects** lets you build property-based conversion rules with a **HighLevel Properties** selector, an **Operator** and an optional **Conversion Value**.

1. Open **Add Custom Objects** from the HighLevel connection.
2. Select the HighLevel property from the correct object group.
3. Choose an operator and enter the value to match.
4. To attach a value, select a numeric property under **Conversion Value**, such as **Opportunity Amount**.
5. Choose **Add**, review the rule and choose **Save**.
6. Test it with a sample record change before using it in a goal.

![Custom object rule with operator and conversion value controls](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/10-custom-object-rule.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=d998cb6d12d4b30c71c222dd51e594b0)

![Choosing a source property from company fields](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/11-company-source-property.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=168bdac06592dc57efc7f5dfa9e442e1)

![Choosing opportunity amount as conversion value](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/12-conversion-value.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=6b6655f2620ba4e4cb9496c16909a478)

A conversion value supplies an amount; it doesn't decide whether the outcome happened. The rule, the event and the goal each play a separate role.

### Create a contact or company event

1. Open **Data → Events Manager** and choose **Create Event**.
2. Enter a clear name, such as **HighLevel Contact Created**, and an event ID, such as `ghl_contact_created`.
3. Select **CRM Event** as the event type and **HighLevel** as the source.
4. Choose **CRM Event** or the relevant property group.
5. Select the record action, such as **Contact Created**. For a company event, select the company action.
6. Save, create a test record in HighLevel, and confirm the event in **Event Logs** with the correct person and company.

![Creating a CRM event sourced from HighLevel](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/13-create-crm-event.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=5f3d3d2de33a9c94a3286b7499d189b1)

### Create an opportunity stage event

1. Choose **Create Event** and select **CRM Opportunity**.
2. Select **HighLevel** as the source and **CRM Opportunity** as the property group.
3. Choose the pipeline, for example **New Business**, then the stage, for example **Qualified**.
4. Name the event **HighLevel Qualified Opportunity** with the event ID `ghl_qualified_opportunity`.
5. Save, move a test opportunity into Qualified, and check the event in **Event Logs**.
6. Confirm the event links to the opportunity, its contact and its company.

![Selecting a HighLevel pipeline and stage for an event](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/14-pipeline-stage-event.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=cf8718e6e5f88d216a3327e480d101b2)

Stages are identified by location and pipeline, so two pipelines can each have a Qualified stage without conflict. Renaming a stage in HighLevel keeps the event working; deleting and recreating it means you need to update the event.

### Stage vs. status

A pipeline **stage** shows where an opportunity sits in your sales process. Opportunity **status** shows whether it is open, won, lost or abandoned. A stage named Closed Won doesn't by itself mean the status changed to won.

![Diagram comparing pipeline stages with opportunity statuses](https://mintcdn.com/stiddle/z_SaLYTbL7bpbXj8/images/gohighlevel/22-stage-vs-status.png?fit=max\&auto=format\&n=z_SaLYTbL7bpbXj8\&q=85\&s=6f8120387e5075695bb356c18ba8bc66)

For won deals, use the status change to **won** as the event. If your process also requires a final stage, include both conditions in the rule. Don't count the same win through both a stage event and a status event in one revenue goal.

### Suggested event plan

| HighLevel change | Suggested event | Count as a conversion? |
| - | - | - |
| Contact created | HighLevel Contact Created | Only if a new contact is a lead outcome for you |
| Contact updated | None (refreshes the record) | No |
| Opportunity created | HighLevel Opportunity Created | Optional, for an opened-opportunity goal |
| Opportunity enters a stage | HighLevel \[Stage] Opportunity | Yes, for that pipeline and stage |
| Opportunity status changes to won | HighLevel Won Opportunity | Yes, for won or revenue goals |
| Opportunity amount changes | None (refreshes the value) | No |
| Record deleted | None | No |

## Pipeline and revenue goals

A goal tracks an outcome, such as a lead becoming qualified, an opportunity being opened, or a deal being won. It uses one or more events and can carry a value, such as pipeline value or revenue.

When a HighLevel opportunity enters a tracked stage, Stiddle links the event to the opportunity, its contact and its company. If the event matches a goal, it counts as a conversion and is attributed across the person's marketing touchpoints and spend.

### Suggested goal plan

| Goal | Event or rule | Value |
| - | - | - |
| New CRM lead | Contact created, or a qualified-lead rule | None, or an agreed fixed value |
| Opened opportunity | New opportunity in the selected pipeline | Optional opportunity amount as pipeline value |
| Qualified pipeline | Entry into Qualified | Opportunity Amount as qualified pipeline value |
| Proposal stage | Entry into Proposal | Opportunity Amount as proposal pipeline value |
| Won opportunity | Status changes to won | Won value; revenue under your recognition policy |
| Acquired customer | First won deal per customer company | Deduplicated customer revenue |

### Configure a goal

1. Open **Data → Goals Manager** and choose **Create Goal**.
2. Enter a **Goal Name**, for example **HighLevel Qualified Pipeline**.
3. Under **Events**, select **HighLevel Qualified Opportunity**.
4. Set **Goal Conversion Value** to **Opportunity Amount**, a fixed value, or no value.
5. Review **View through Configuration** if it applies to your attribution setup.
6. Under **Advanced**, choose whether to include matching events that already exist in Stiddle. This doesn't recreate stage history from before the connection.
7. Save, then test with a sample opportunity.

![Goal configuration using a pipeline event and Opportunity Amount](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/15-goal-opportunity-amount.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=575c77db0fc9a05dffb008c9663596e7)

### Counting and value

Decide what each goal counts before reporting: events, unique opportunities, individuals or customer companies. One person can have several opportunities, and an existing customer can win another deal, so only label a won-opportunity count as "new customers" if it excludes repeat wins.

Also decide whether goals count only the first time an opportunity enters a stage or every time, how reopened deals behave, and whether later amount changes should update past goal value.

Don't add Qualified, Proposal and Won values together and call the total revenue. They can be the same opportunity at different steps. Use stage goals for pipeline analysis and a separate won goal for revenue.

![Diagram showing one \$25,000 deal counted in Qualified, Proposal and Won goals](https://mintcdn.com/stiddle/z_SaLYTbL7bpbXj8/images/gohighlevel/23-goal-values.png?fit=max\&auto=format\&n=z_SaLYTbL7bpbXj8\&q=85\&s=781f3cb11206fb408fbc744c01d1f7eb)

## Attribution and acquisition costs

Once events and goals are set up, Stiddle connects outcomes to each person's marketing journey and their account and opportunity. With spend data connected, you get cost-per-outcome reporting. Your attribution model decides how credit and value are shared across touchpoints.

| Question | Goal to use | What you get |
| - | - | - |
| What creates sales opportunities? | Opened opportunity | Cost per opened opportunity and attributed pipeline |
| What produces qualified pipeline? | Qualified stage | Cost per qualified opportunity and qualified pipeline value |
| Which channels help deals progress? | Separate stage goals | Contribution and progression by stage |
| What generates won business? | Won / revenue | Attributed won value and revenue ROAS |
| What does it cost to acquire a customer? | Acquired customer | CAC for your defined customer unit |

### Example

One reporting cohort has \$12,000 in marketing spend, 40 opened opportunities, 20 opportunities entering Qualified, and 8 newly acquired customer companies. The qualified opportunities carry \$100,000 of pipeline value, and the customer wins carry \$40,000 of revenue.

| Metric | Calculation | Result |
| - | - | - |
| Cost per opened opportunity | \$12,000 / 40 | \$300 |
| Cost per qualified opportunity | \$12,000 / 20 | \$600 |
| Marketing-spend CAC | \$12,000 / 8 new customer companies | \$1,500 |
| Qualified pipeline per dollar of spend | \$100,000 / \$12,000 | 8.33x |
| Revenue ROAS | \$40,000 / \$12,000 | 3.33x |

These numbers are illustrative. Use the same population, currency and time period for every metric. Deal creation, stage entry and win dates can fall in different periods, so choose between a conversion-period view and an acquisition-cohort view.

Goal metrics include Goal Count, Cost Per Goal, Goal Value and Goal ROAS. Label pipeline-valued goals as pipeline so their ratio isn't mistaken for revenue ROAS. A fully loaded CAC also includes the sales and operating costs you choose to allocate, beyond ad spend.

## Alternative ingestion routes and sync back to HighLevel

The managed connector is the standard setup. API, webhook, CSV and warehouse routes are available for custom deployments. Use one route per dataset and one consistent record key so overlapping feeds don't create duplicate events.

### API and webhook integration

For a custom integration, send data through the Stiddle ingestion API and authenticate to HighLevel separately. Fetch every page of records across all opportunity statuses, keep location and record IDs, and set the HighLevel `Version` header for each endpoint.

| HighLevel API resource | Use |
| - | - |
| Contacts search/list (location-scoped) | Enumerate contacts |
| `GET /contacts/:contactId` | Retrieve a single contact |
| `GET /businesses/` with location ID | Enumerate customer businesses |
| `GET /contacts/business/:businessId` | List contacts for a business |
| `GET /opportunities/search` | Enumerate opportunities across all statuses |
| `GET /opportunities/:id` | Retrieve a single opportunity |
| `GET /opportunities/pipelines` | Retrieve pipeline and stage definitions |

Opportunity search defaults to open opportunities, so include won, lost and abandoned statuses explicitly. Don't rely on the contacts-by-business endpoint as your only contact source, because contacts without a business won't appear.

If you receive HighLevel webhooks directly, use these notifications:

| HighLevel notification | Use |
| - | - |
| `ContactCreate` | New contact event |
| `ContactUpdate` | Refresh contact properties |
| `OpportunityCreate` | New opportunity event |
| `OpportunityStageUpdate` | Evaluate stage transitions |
| `OpportunityStatusUpdate` | Evaluate won, lost or reopened status |
| `OpportunityMonetaryValueUpdate` | Refresh opportunity value |
| `OpportunityDelete` / `ContactDelete` | Remove or archive the record |

Verify the `X-GHL-Signature` header on every delivery, route by location ID, and deduplicate retries using the delivery ID. In stage and status notifications, `dateAdded` is when the record was created, not when the stage changed, so use the transition or received time as the event time.

See HighLevel's [webhook integration guide](https://marketplace.gohighlevel.com/docs/webhook/WebhookIntegrationGuide/).

### CSV import

For a one-time backfill, export contacts, customer businesses and opportunities as separate files. Include location IDs, record IDs, relationship keys, timestamps, and stage and value fields. Import each file through **Data → Import** with the matching record type, choose how duplicates are handled, preview the mappings and check dates before importing.

### Warehouse connection

If your HighLevel data is already in a warehouse, use curated tables with the same keys and relationships described above. Include modification times, deletion markers where available, and pipeline definitions. A current snapshot doesn't include stage history unless you also keep a change-history table.

### Sync back to HighLevel

Sending Stiddle data back to HighLevel is set up separately from the inbound sync. Common uses:

* Write a Stiddle profile link or engagement summary to a contact custom field.
* Update an account score in a custom field.
* Apply or remove a tag based on Stiddle audience membership.
* Add a contact note with selected activity history.

Sync back requires the matching write scopes (`contacts.write`, `opportunities.write` or `businesses.write`) for the operations you enable. Stiddle matches existing records by location and record ID and doesn't change CRM-owned fields such as stage and amount. Audience tags are added and removed as membership changes, and other tags are left alone. Test on a small set of records first. Contact your Stiddle team to enable sync back.

## Validation and troubleshooting

Use **Data → Sync Logs** to confirm records arrived, **Event Logs** to confirm events fired, and **Goals Manager** or reports to confirm conversions. A record update on its own doesn't mean a goal should have counted.

![HighLevel sync logs and batch results](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/16-sync-logs.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=2da92b38065d3bdf864e489f0f96a9ab)

### Read a sync result

Each sync log shows the connection, location, record type, sync time and batch result. Rows synced, inserted and updated count record operations, not new leads, stage changes or customers.

Open a batch to compare previous and current property values for a record. In the example below, an opportunity stays open at \$25,000 while its stage changes from New to Qualified. That stage change matches a Qualified event; an update that only changes a timestamp doesn't.

![Sync log detail showing an opportunity moving to Qualified](https://mintcdn.com/stiddle/TQbD3gBWYqGjV5Hm/images/gohighlevel/17-sync-log-stage-change.png?fit=max\&auto=format\&n=TQbD3gBWYqGjV5Hm\&q=85\&s=d9bbbac7eacb6c6a1a69ce4d362b7b6f)

### Acceptance tests

Run these in a test sub-account or with clearly labeled test records before using reports in production.

| Test | Expected result |
| - | - |
| Authorize the intended location | Stiddle shows the correct connection and location ID |
| Sync contacts, companies and opportunities | IDs, counts and relationships match HighLevel |
| Include open, won, lost and abandoned opportunities | No records are hidden by a status filter |
| Create a contact linked to a business | Contact and company appear with the correct relationship |
| Link an opportunity to that contact | Deal links to its person and company |
| Move the opportunity into Qualified | One stage event appears with the correct pipeline |
| Update a non-stage field | Record refreshes without another stage conversion |
| Move the opportunity out of and back into the stage | Counting matches your goal settings |
| Change status to won | The won goal counts once |
| Change the amount after qualification | Goal value behaves as configured |
| Rotate or revoke credentials | The connection shows the change and syncing can be restored |
| Review reporting | Goal unit, currency, value and spend basis are clear |

### Troubleshooting matrix

| Symptom | Check | Next action |
| - | - | - |
| Connection fails | Credential type, location access and scopes | Reauthorize OAuth or replace the token with a correctly scoped one |
| Records are missing | Location, permissions, filters and opportunity statuses | Compare counts with the same filters and re-sync |
| Companies look wrong | Customer businesses vs. agency company data | Check the business relationships in HighLevel |
| Contact has no company | Business relationship in HighLevel | Link the contact to a business in HighLevel and re-sync |
| Opportunity has no person | The opportunity's contact | Make sure the contact exists and has synced |
| Stage names are missing | Pipeline and stage definitions | Re-sync and review mappings |
| Stage event doesn't fire | Source, pipeline, stage and an actual transition | Move a test opportunity into the stage and check Event Logs |
| Goal counts twice | Overlapping stage and status events, or repeat stage entries | Use one event per outcome and review goal counting |
| Won goal doesn't match | Status vs. stage name | Use the status change to won |
| Old conversions look recent | Creation, transition and import times | Check event times in Event Logs; pre-connection history can't be recreated |
| Token connection stopped updating | Token rotation, scope changes and last sync time | Update the token in Stiddle and re-sync the missed period |
| Goal value is wrong | Amount field, currency and later value changes | Check the Opportunity Amount mapping and goal value settings |

### Keep a configuration record

Record your workspace, location, authentication method, approved scopes, ingestion route, field mappings, pipeline and stage IDs, event rules, goal counting and value settings, and support owner. Keep tokens and other secrets in a password manager, not in this record.


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