Skip to content

Start from workflow/starter.json (webhook, normalizer, rule score) or your finished lesson workflow.

Exercise 1: Alert sales on hot leads

Task: Replace Alert Sales (Exercise 1) with a Slack, Telegram or email message containing the lead's name, score, summary, next step and a link to the contact in GHL.

Done when: a hot lead triggers the alert within seconds; warm/cold leads don't.

Hint

The GHL contact URL is https://app.gohighlevel.com/v2/location/<location_id>/contacts/detail/<contact_id>; carry location_id through from the normalizer.

Exercise 2: Never qualify the same contact twice

Task: If GHL sends the same contact_id again (retries or update triggers), skip AI and write-back and respond {"skipped": "already qualified"}.

Done when: posting the same lead twice (without dry run) writes to GHL only once.

Hint

Remove Duplicates → Remove Items Processed in Previous Executions, value {{ $json.contact_id }}, before AI Qualify. Route its "discarded" case to a separate Respond… or check the existing ai-qualified tag in the incoming payload.

Exercise 3: Test write-back without GoHighLevel

Task: Build a mock GHL API in n8n that accepts POST …/contacts/:contactId/tags and /notes, records what it received, and lets you read the recorded calls. Point a copy of the bridge at it and prove the tag and note requests are correct.

Done when: after one non-dry-run call against the mock, the recorded calls show both requests with the Version header and the expected bodies.

Hint

A Webhook with path parameters (mock-ghl/contacts/:contactId/:kind) + a Code node writing to $getWorkflowStaticData('global'). n8n serves webhooks with path parameters under the webhook's ID: /webhook/<webhookId>/mock-ghl/…. Replace AI Qualify with an Edit Fields node returning a fixed output so you don't need OpenAI either.

Stretch: Move the opportunity

Also create or move an opportunity: hot leads into the "Call now" stage of your pipeline via the LeadConnector opportunities API.