GoHighLevel call tracking integration

GoHighLevel's Inbound Webhook trigger receives our qualified-call payload directly — no middleware needed. Each qualified call creates or updates a contact by phone number and can kick off any GHL automation: tags, pipelines, SMS follow-up, or appointment booking.

Integrations / GoHighLevel

What you get

Every qualified call (passing your duration and screening rules) is delivered to GoHighLevel within about a minute: caller number, duration, timestamps, the campaign that generated the call, ad click IDs when present, and a recording link.

Step A — callstracking.com side

  1. Create an account and set up your campaign (2 minutes).
  2. Go to Dashboard → Integrations → Webhook / CRM.
  3. Paste the webhook URL from GoHighLevel (Step B) and choose a signing secret.
  4. Save. Qualified calls now POST to that URL automatically.

Step B — GoHighLevel side

  1. In GoHighLevel, open the sub-account → Automation → Workflows → Create Workflow → start from scratch.
  2. Add the trigger "Inbound Webhook". GHL shows a unique webhook URL — copy it.
  3. Paste that URL into the callstracking.com webhook integration (Step A above) and save.
  4. Make one qualified test call (or use the sample payload below) so GHL captures the payload shape, then map fromE164 → contact phone and campaignName → a custom field or tag.
  5. Add your follow-up actions — e.g. Create/Update Contact, Add Tag "qualified-call", assign to a pipeline stage, or notify the owner by SMS.
  6. Publish the workflow.
  • Inbound Webhook is a GHL premium workflow trigger — it must be enabled on the agency plan.
  • Use campaignName to route different campaigns to different pipelines with workflow filters.

The payload

Sent as JSON with content-type application/json. The recordingUrl opens in a signed-in callstracking.com session.

{
  "type": "qualified_call",
  "callId": "clx1abc...",
  "source": "DNI",
  "startedAt": "2026-08-14T17:21:09.000Z",
  "qualifiedAt": "2026-08-14T17:23:41.000Z",
  "durationSec": 152,
  "fromE164": "+15551234567",
  "toE164": "+12138321924",
  "campaignId": "cmsam...",
  "campaignName": "Google Ads — Plumbing",
  "channel": "GOOGLE_ADS",
  "recordingUrl": "https://callstracking.com/api/recordings/clx1abc...",
  "clickIds": { "gclid": "..." },
  "utm": { "utm_source": "google", "utm_campaign": "plumbing" }
}

Verifying the signature

Every delivery is signed with your secret: header x-ct-signature: sha256=<hmac> over the raw body, plus x-ct-event: call.qualified. Platforms like Zapier and GoHighLevel can skip verification (the URL itself is secret); verify when posting to your own server:

// Node.js — verify the x-ct-signature header
import { createHmac } from "node:crypto";

const expected = "sha256=" +
  createHmac("sha256", process.env.CT_WEBHOOK_SECRET)
    .update(rawRequestBody)   // the exact raw body string
    .digest("hex");

const valid = expected === req.headers["x-ct-signature"];

Troubleshooting