Fix: GoHighLevel webhook not receiving data
GHL says the webhook fired but the receiving system has nothing. Here's the diagnostic for URL, headers, payload, and connectivity issues.
Symptoms — what you're seeing
- You set up a webhook in GoHighLevel to send data to an external system (n8n, Zapier, a custom API) but the receiving end shows nothing
- GHL shows the webhook action step as "completed" in the workflow log, but the target system has no record of receiving a request
- The webhook worked during initial testing but stopped receiving data in production
- The receiving system shows the request arrived but the body is empty or malformed
- Some events come through but others are silently dropped
Why this happens
GHL webhook failures are almost always one of four things: a wrong URL, a wrong HTTP method, a missing or incorrect Content-Type header, or the receiving system not being ready to accept the request. The tricky part is that GHL often reports the webhook step as "successful" even when the receiving system rejected it with a 4xx/5xx — GHL considers "sent" as "done."
The four most common causes
1. Wrong URL — test vs. production. If you're sending to n8n, the test webhook URL and the production webhook URL are different. The test URL only works when you're actively listening in the n8n editor. The production URL works 24/7 but only when the workflow is activated.
2. Missing Content-Type header. GHL doesn't always set Content-Type: application/json by default on webhook actions. If the receiving system expects JSON but GHL sends the payload without the header, the receiver may parse it as plain text or reject it entirely.
3. Payload body not configured. GHL webhook actions have a separate "Body" section where you map the variables you want to send. If you don't explicitly add variables to the body, GHL sends an empty POST request — the webhook fires, but there's no data in it.
4. Receiving system is down or unreachable. If the target URL returns a 5xx error or times out, GHL may retry up to 3 times, then give up. If the target is behind a firewall, VPN, or requires authentication, GHL can't reach it at all.
The fix, step by step
- Test the URL independently. Open your terminal and send a test request to the webhook URL:
curl -X POST "YOUR_WEBHOOK_URL" \ -H "Content-Type: application/json" \ -d '{"test": "from_terminal", "timestamp": "'$(date -Iseconds)'"}'If this fails, the problem is the URL or the receiving system — not GHL. - Check the URL format. Common mistakes:
- Trailing slash mismatch (some systems are strict about
/webhookvs/webhook/) - Using HTTP instead of HTTPS (most webhook receivers require HTTPS)
- For n8n: using the test URL instead of the production URL
- Accidentally including query parameters that shouldn't be there
- Trailing slash mismatch (some systems are strict about
- Add the Content-Type header in GHL. In the webhook action step, under Headers, explicitly add:
Key: Content-Type Value: application/json
- Map the payload body. In the webhook action's Body section, add every variable you need. Use GHL's variable picker to insert them:
{ "contact_id": "{{contact.id}}", "contact_name": "{{contact.name}}", "contact_email": "{{contact.email}}", "contact_phone": "{{contact.phone}}", "event": "contact_created" } - Verify the GHL workflow is Published (not Draft). See the GHL workflow not triggering guide if the entire workflow isn't firing.
Common variations
- "Webhook sends but body is empty" — you didn't map variables in the Body section. GHL sends the POST with an empty body by default.
- "Webhook worked for weeks then stopped" — the receiving system's URL changed (common with n8n after re-saving a workflow, or ngrok tunnels expiring on self-hosted setups).
- "Some contacts trigger the webhook, others don't" — the GHL workflow has trigger filters that silently exclude certain contacts. Remove all filters and test.
- "Webhook fires but receiving system shows wrong data" — GHL variable syntax changed, or you're referencing custom fields that don't exist on all contacts. Test with a contact that has all fields populated.
When this isn't the issue
- If the receiving system gets the request but the data looks wrong, the issue is in your payload mapping — not the webhook delivery
- If GHL logs show the webhook step erroring (not just "completed"), click on the step to see the HTTP response code and body — that tells you exactly what the receiving system rejected
- If you're using GHL's native integrations (not custom webhooks), the issue might be an OAuth token expiration — re-authenticate the integration
Need this workflow customized or debugged? Book a 30-min scope call →
Stuck configuring this workflow?
I build and fix n8n workflows for agencies and SaaS teams. 30-minute scope call — bring the problem, leave with an estimate.