Integrations

GoHighLevel Two-Workflow Snapshot Integration

Connect a GoHighLevel agency Location to Cooledge using the two-workflow Snapshot, so marketing-stage contacts and opportunities stay in sync with Cooledge jobs, quotes and invoices.

Updated 06/06/2026

GoHighLevel Two-Workflow Snapshot Integration

This guide is for agencies who run GoHighLevel (GHL) and want a Location to talk to Cooledge.

Available on the Growth and Scale plans. The GoHighLevel integration is part of Cooledge's API and integrations access, which Starter plans do not include. Upgrade to Growth or Scale to connect a Location.

The integration ships as a single GHL Snapshot that contains two workflows. One workflow sends contacts and opportunities from GHL into Cooledge. The other workflow receives Cooledge events back out into GHL so your pipeline reflects what happens once a lead becomes real work.

The division of responsibility is deliberate:

  • GHL is the source of truth for marketing-stage contacts and opportunities. Lead capture, nurture sequences and pipeline stages live in GHL.
  • Cooledge is the source of truth for jobs, quotes and invoices. Once a contact becomes a customer with real work attached, Cooledge owns that record and reports state changes back.

You apply the Snapshot once per Location, set a few custom values, paste in one URL from Cooledge and then choose which Cooledge events you want pushed back into GHL.

The GHL workflows list after applying the Snapshot, showing the Cooledge inbound and outbound workflows both published

What the Snapshot installs

Applying the Snapshot to a Location adds four things:

  • Two workflows. An inbound workflow sends GHL contacts and opportunities into Cooledge. An outbound workflow receives Cooledge events back into GHL. Both arrive in Draft.
  • Two custom values. cooledge_inbound_url and cooledge_inbound_secret. They arrive empty and you fill them in during setup (step 3).
  • Three contact tags. cooledge-quote-sent, cooledge-quote-accepted and cooledge-deposit-paid. The outbound workflow applies these to a contact as the matching Cooledge events arrive. They are optional: if you do not want them, delete the tag actions from the outbound workflow.
  • One demo pipeline. A pipeline named "Pipeline" with the stages New Lead, Contacted, Ready to Quote, Quote Sent and Quote Accepted. It is a basic starting example so the workflows have stages to point at. Replace it with your own pipeline and re-link the stages when you finish the outbound workflow (step 7).

Setup walkthrough

  1. Import the Snapshot. Open the share link for the Cooledge reference Snapshot. GHL will add it to your agency account as an available Snapshot.
  2. Apply the Snapshot to a Location. Pick the Location you want connected to Cooledge and load the Snapshot into it. This creates both workflows in that Location.
  3. Set the two custom values. In Cooledge, open the GHL settings card to find the values you need. In the GHL Location go to Settings → Custom Values and set:
    • cooledge_inbound_url to the inbound URL shown on the Cooledge card.
    • cooledge_inbound_secret to the inbound secret shown on the Cooledge card.
  4. Publish the inbound workflow. Snapshot imports arrive in Draft. The inbound workflow needs no extra configuration, so open it and publish it first. Leave the outbound workflow in Draft for now: GHL will not let you save it until its trigger has received a sample request, and the next two steps produce that sample.
  5. Copy the agency outbound trigger URL into Cooledge and choose events. The outbound workflow starts from a GHL Inbound Webhook trigger that gets its own fresh URL in this Location after import (the URL exists even while the workflow is a draft). Copy it into the matching field on the Cooledge GHL settings card, then select the event types you want delivered. Send only what your GHL automations actually use. See the costs note below for why this matters.
  6. Click "Send test event" on the Cooledge card. Once the subscription is created, the card shows a Send test event button. It delivers a signed, clearly test-marked quote.accepted sample to the trigger URL with the full production key set. That single click gives GHL the sample request its trigger needs. (No Cooledge access at hand? The no-code fallback is to create a test contact with an email or phone in the GHL Location, open an opportunity in the imported pipeline and move its stage, with lead.created among the selected events.)
  7. Finish and publish the outbound workflow. Open it, pick the most recent request in the trigger's mapping reference, then re-link your pipeline and the target stage in each branch (pipeline and stage IDs are per Location, so imported opportunity actions arrive with unlinked references). Save and publish.

The Cooledge GoHighLevel settings card showing the Snapshot share link, the inbound URL and secret, the outbound trigger URL field and the outbound event checkboxes

Inbound custom-data contract

The inbound workflow uses a GHL Webhook action to call Cooledge. That action must set the custom-data pairs below. These are the fields Cooledge reads to identify the contact and opportunity and to dedupe repeat deliveries.

The inbound workflow in the GHL builder, with a Pipeline Stage Changed trigger feeding the Webhook action that calls Cooledge

KeyValueRequiredNotes
opportunity_id{{opportunity.id}}YesDedupe key. If this is missing the request is rejected with HTTP 422.
contact_id{{contact.id}}Required in practiceCooledge still processes the lead if it is absent, but the lead is flagged as missing its contact link and degrades gracefully.
snapshot_versionv1YesLiteral string. Lets Cooledge map the payload to the right contract version.
pipeline_stage{{opportunity.pipeline_stage}}OptionalMirrors the GHL pipeline stage onto the Cooledge lead and stays current as later deliveries report stage changes.
cooledge_inbound_secret{{custom_values.cooledge_inbound_secret}}FallbackThe x-cooledge-ghl-secret header is the primary carrier of the secret and takes precedence. This custom-data pair is a fallback for setups where the header cannot be set.

Two failure modes are worth calling out:

  • opportunity_id missing returns HTTP 422 and the request is not processed. The opportunity id is the dedupe key, so Cooledge cannot accept the lead without it.
  • contact_id missing still processes the lead, but Cooledge flags it as incomplete because it has no GHL contact to link back to.

Available outbound event types

Eight outbound event types are available. The outbound workflow fires when Cooledge sends one of these to your Location:

  • customer.created
  • customer.updated
  • lead.created
  • lead.updated
  • lead.converted
  • quote.sent
  • quote.accepted
  • quote.paid

Every payload uses the same envelope plus a correlation block that lets GHL match the event back to the right contact and opportunity. Here is an example quote.accepted payload:

{
  "version": "v1",
  "event_type": "quote.accepted",
  "event_id": "evt_01HZX9Q7M3K8F2N4P6R8T0V2W4",
  "business_id": "biz_8f2a1c9e",
  "occurred_at": "2026-06-06T03:21:44.512Z",
  "external_ghl_contact_id": "cont_7Yh2KpQ9",
  "external_ghl_opportunity_id": "opp_3Df8La1Z",
  "customer_name": "Jordan Avery",
  "customer_email": "jordan.avery@example.com",
  "customer_phone": "+61400111222",
  "quote_id": "quote_a1b2c3d4",
  "customer_id": "cust_5Gk9Rm2P",
  "quote_reference": "Q-1042",
  "accepted_total": 4850.00,
  "accepted_at": "2026-06-06T03:21:44.512Z",
  "job_number": "J-2031"
}

The envelope is always version, event_type, event_id, business_id and occurred_at. The correlation block is external_ghl_contact_id, external_ghl_opportunity_id, customer_name, customer_email and customer_phone. The remaining keys are flat top-level fields carrying the event-specific detail. For quote.accepted those are quote_id, customer_id, quote_reference, accepted_total, accepted_at and job_number. The customer name, email and phone on quote events reflect the point-in-time snapshot the quote was sent with, while the two external_ghl_* ids are the live correlation keys.

Lead events carry the lead record itself. Here is an example lead.created payload:

{
  "version": "v1",
  "event_type": "lead.created",
  "event_id": "evt_01HZXA2B7C9D1E3F5G7H9J1K3M",
  "business_id": "biz_8f2a1c9e",
  "occurred_at": "2026-06-12T01:05:12.118Z",
  "external_ghl_contact_id": "cont_7Yh2KpQ9",
  "external_ghl_opportunity_id": "opp_3Df8La1Z",
  "customer_name": "Jordan Avery",
  "customer_email": "jordan.avery@example.com",
  "customer_phone": "+61400111222",
  "lead_id": "lead_9Xw4Tn6V",
  "customer_id": "cust_5Gk9Rm2P",
  "name": "Jordan Avery",
  "email": "jordan.avery@example.com",
  "phone": "+61400111222",
  "status": "new",
  "source": "ghl",
  "type": "General",
  "site_id": null
}

lead.updated carries the same keys plus archived (boolean). lead.converted fires when a lead is linked to a customer record and carries lead_id, customer_id and customer_was_created alongside the correlation block.

A few rules for consumers:

  • Payloads are additive only. New keys may appear over time. Existing keys keep their meaning.
  • One shape per event type. An event type has the same payload shape no matter which part of Cooledge produced it. A workflow that reads name off lead.updated works for every origin.
  • Ignore unknown keys. Do not fail a workflow because a key you did not expect showed up.
  • Dedupe on event_id. The same event may be delivered more than once. Treat event_id as the idempotency key.
  • Do not assume delivery order. Each delivery is retried independently, so events can arrive out of order. Use occurred_at to sequence events for the same lead or customer.

Costs note

The inbound side is free. The GHL Webhook action that calls Cooledge does not consume GHL execution credits.

The outbound side is not free. The outbound workflow is started by GHL's premium Inbound Webhook trigger, which GHL bills per execution. Every Cooledge event you choose to send becomes one billed GHL execution. That is why step 5 asks you to pick outbound events deliberately. Turn on only the events your GHL automations actually act on.

Cooledge also protects your execution budget on repeats: an inbound delivery that changes nothing (a retry or duplicate) produces no outbound events at all.

Security and forward compatibility

Outbound delivery is currently protected by two things working together:

  • The outbound trigger URL is unique and obscure per Location. It is not guessable and you should treat it as a secret.
  • Cooledge sends an HMAC signature header with each outbound delivery so the Location can verify the payload came from Cooledge.

This is the current approach, not the final one. A future release will add a Cooledge marketplace app with GHL OAuth that replaces the URL-plus-header scheme with native signed delivery through the marketplace.

Because of that, do not build long-lived business-critical workflows that assume this URL-plus-header scheme is permanent. When the marketplace app ships, the delivery mechanism will change and you will need to re-point your outbound automations.

The outbound workflow in the GHL builder, starting from the Inbound Webhook trigger and branching per event type into opportunity updates and tags

Need a hand with an integration? Contact support