When you build a custom signup form, checkout system, or backend service, you often need GoHighLevel to ingest that data instantly without paying for Zapier or Make as an intermediary. HighLevel’s Inbound Webhook trigger gives you a unique endpoint inside your sub-account that receives HTTP POST requests and dumps the raw JSON straight into your workflow context.
I wired this up recently to push user registrations from a custom Next.js portal directly into a client sub-account. Here is how to configure the trigger, send test payloads, map nested JSON keys, and dodge the silent failure bugs that usually trip people up.

How the Inbound Webhook Trigger Works
An inbound webhook in HighLevel is just an HTTP listener. Rather than polling an external API every few minutes, your automation triggers the second a third-party service posts data to your URL.
When HighLevel receives the request, it exposes the full payload under the inboundWebhook context key. You can then reference incoming strings, numbers, booleans, and nested objects across your downstream actions.
Keep these quirks in mind before you start:
- HTTP Method: HighLevel only listens for
POSTrequests with aContent-Type: application/jsonheader. - No Automatic Contact Creation: The trigger just catches raw data. It will not create or update a contact until you explicitly add a “Create/Update Contact” action right after it.
- Response Time: Under normal loads, the webhook endpoint returns an HTTP 200 within 200ms to 400ms.
Step 1: Create the Inbound Webhook Trigger
Open your sub-account and go to Automation > Workflows. Create a new workflow from scratch.
- Click Add New Trigger.
- Search for and select Inbound Webhook.
- HighLevel generates a unique webhook URL formatted like
https://services.leadconnectorhq.com/hooks/workflows/.... - Click Copy Webhook URL and keep the workflow trigger drawer open.
If you juggle multiple client sub-accounts, double-check that you’re in the right workspace before grabbing the URL. If you need to verify environments via API first, you can find your sub-account Location ID.
Step 2: Send a Sample Payload via cURL or Postman
HighLevel needs a real sample payload before it lets you select merge keys in downstream workflow actions. Do not publish the workflow yet—leave the trigger drawer open on the “Listening for event…” screen.
Here is a test cURL command containing contact details, nested transaction data, and custom tracking parameters:
curl -X POST "https://services.leadconnectorhq.com/hooks/workflows/YOUR_WORKFLOW_TRIGGER_ID" -H "Content-Type: application/json" -d '{ "first_name": "Alex", "last_name": "Morgan", "email": "alex.morgan@example.com", "phone": "+15552345678", "company_name": "Acme Corp", "transaction": { "id": "tx_894102", "amount": 149.00, "currency": "USD", "plan": "Pro Annual" }, "source": "marketing_portal" }'Swap out YOUR_WORKFLOW_TRIGGER_ID with the URL you copied in Step 1 and run the command. You should get back {"success": true}.
In the workflow builder, the trigger status will switch from “Listening…” to “Sample Data Received”. Select the incoming request to save the schema into your workflow session and click Save Trigger.
Step 3: Create or Update the Contact
Because the webhook trigger only holds data in memory, you need to tell HighLevel what to do with it.
Click the + icon under your trigger and add the Create/Update Contact action. Map your contact fields using the dynamic webhook paths:
- First Name:
{{inboundWebhook.first_name}} - Last Name:
{{inboundWebhook.last_name}} - Email:
{{inboundWebhook.email}} - Phone:
{{inboundWebhook.phone}} - Company Name:
{{inboundWebhook.company_name}}
If you need default values or fallbacks, you can also use custom values in GoHighLevel alongside these trigger variables.
Step 4: Map Nested JSON and Arrays
Real-world webhooks from Stripe, Shopify, or custom backends rarely send flat key-value pairs. You’ll usually get nested objects and arrays.
HighLevel handles nested structures via standard dot notation. You can either pick them from the UI field selector or type the merge tags manually.
Here is a nested payload with nested customer objects and array items:
{ "event": "checkout.completed", "customer": { "name": "Sarah Connor", "email": "s.connor@example.com" }, "billing": { "address": { "city": "Los Angeles", "state": "CA", "postal_code": "90001" } }, "tags": [ "vip_tier", "early_adopter" ]
}To pull values out of that payload inside subsequent workflow steps:
- Customer Email:
{{inboundWebhook.customer.email}} - Billing City:
{{inboundWebhook.billing.address.city}} - First Tag:
{{inboundWebhook.tags[0]}}
If you need to push processed data to another API later in the run, you can send custom values and contact fields via outbound webhooks.
Step 5: Testing with a Node.js Ingest Script
When integrating a custom backend, write a quick test script to verify response codes and error handling before pushing to production. Here is a minimal Node.js script using native fetch:
const sendToHighLevel = async () => { const endpoint = 'https://services.leadconnectorhq.com/hooks/workflows/YOUR_WORKFLOW_TRIGGER_ID'; const payload = { first_name: 'Jordan', last_name: 'Hayes', email: 'jordan.hayes@example.com', phone: '+15559876543', metadata: { signup_source: 'dashboard_app', tier: 'enterprise' } }; try { const response = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(payload) }); const data = await response.json(); console.log(`Status: ${response.status}`); console.log('Response body:', data); } catch (error) { console.error('Webhook push failed:', error.message); }
};
sendToHighLevel();Run it with node sendToHighLevel.js. Then check the Execution Logs tab inside your workflow to verify that the payload parsed without missing fields.
Common Webhook Trigger Bugs and Fixes
Inbound webhooks can fail silently when payload formats don’t match expectations. Here are the three most common gotchas:
1. Workflow Never Executes (Trigger Not Firing)
If your sending app gets an HTTP 200 but nothing appears in the Execution Logs:
- Make sure the workflow is toggled to Published, not Draft.
- Turn on Allow Re-entry in Workflow Settings if you test with the same email repeatedly.
- Check if you deleted and recreated the trigger node. Doing so generates a brand-new webhook URL—your backend might still be sending to the old one.
For more edge cases, see our complete guide on fixing workflow webhooks not firing.
2. Blank Merge Fields in Contact Records
If the workflow runs but fields end up blank, your JSON key path doesn’t match the incoming payload. Webhook keys are case-sensitive: {{inboundWebhook.Email}} evaluates to null if the payload sent {"email": "..."}.
3. Empty Array Mapping
If your payload sends an empty array (like "tags": []) and your action references {{inboundWebhook.tags[0]}}, HighLevel leaves that field blank. Use an If/Else condition branch before mapping array items if your server might send empty lists.
Securing Inbound Payloads
Inbound webhook URLs are public endpoints. Anyone who finds the URL can send dummy requests. A simple way to secure it is with a pre-shared token:
- Have your backend pass an auth token in the payload body, like
{"auth_token": "secret_token_123"}. - Add an If/Else condition action right after the Inbound Webhook trigger.
- Check whether
{{inboundWebhook.auth_token}}matches your secret string. - Send valid requests down the “Authorized” branch and drop or flag invalid requests.
For larger integrations requiring OAuth 2.0 or scoped permissions, consult the HighLevel API and Webhook Documentation.
Frequently Asked Questions
Does HighLevel support GET requests on Inbound Webhook triggers?
No. Inbound workflow webhooks only accept HTTP POST requests. A GET or PUT will return a 405 Method Not Allowed error.
Can I trigger an inbound webhook using URL query parameters?
While query parameters can pass through, parsing is much more reliable when you send data as a JSON payload in the request body.
What is the payload size limit for HighLevel inbound webhooks?
Payloads are generally capped at 5 MB per request. Keep payloads lean and avoid passing raw base64-encoded files—pass a hosted file URL instead.
Do inbound webhooks consume API rate limits?
No. Inbound webhook triggers do not count against standard REST API rate limits on services.leadconnectorhq.com, though HighLevel will throttle abusive traffic spikes.
Next Steps
Once your webhook is reliably catching payloads, you will probably want to trigger automated texts or emails. If your leads arrive at all hours, check out our tutorial on setting up SMS quiet hours in GoHighLevel workflows so you don’t wake people up at 2 AM.

