Quick overview
This workflow receives website form leads via a webhook, uses OpenAI to classify intent and urgency, scores and routes each lead with custom rules, and then creates or updates the contact in HubSpot while optionally creating a follow-up task for qualified leads.
How it works
- Receives a new lead submission via a POST webhook.
- Validates and pre-screens the lead details (especially email domain and message content) to flag spam, disposable emails, and other risk signals.
- Searches HubSpot for an existing contact by email to preserve the current owner when a match is found.
- Sends the lead details and message to OpenAI Chat Completions to return a JSON classification for intent, urgency, and a short summary.
- Combines the checks, HubSpot lookup result, and AI output to calculate a score from 0 to 100, assign a tier (A/B/C or rejected), pick a route, and select an owner ID.
- Stops and returns a “rejected” webhook response for spam/job/disposable or invalid leads, otherwise upserts the contact in HubSpot with scoring fields and notes.
- Creates a HubSpot task for tier A and B leads with an appropriate due time (A in 1 hour, B tomorrow) and returns a “routed” webhook response with the scoring details.
Setup
- Create a HubSpot private app with contacts read and write scopes, add its token as a HubSpot App Token credential, and select it on every HubSpot HTTP Request node.
- Add an OpenAI credential and select it on the "AI: read the message" node.
- Create the HubSpot contact properties used by the workflow (lead_fit_score, lead_tier, lead_route, lead_intent, lead_check_notes, ai_lead_summary). The main sticky note lists each type and its dropdown options.
- Replace the placeholder HubSpot owner IDs in the Config node (owner_enterprise, owner_smb, owner_support) with real numeric owner IDs. Left as placeholders or blank, new contacts and tasks are created without an owner.
- Activate the workflow, copy the production webhook URL (path /new-lead), and have your form POST firstname, lastname, email, company, website, jobtitle, company_size, country, budget and message.
Requirements
- HubSpot account (the free CRM works) with a private app token
- OpenAI API key
Customization
- Points, thresholds and routes: the "Score and route" Code node
- Free and disposable email lists: the "Check the lead" Code node
- Swap the webhook for a HubSpot, Typeform or Tally trigger, and map the fields to the same names in "Check the lead"
Additional info
Limitations: writes contacts and tasks only, no companies or deals. The score comes from fixed rules; AI only reads intent and urgency. The free (11) and disposable (8) email domain lists are starter lists, so extend them.
Testing: run on n8n 2.1.5 with 5 sample leads against a demo HubSpot account, including the rejected path. The AI step ran through an OpenAI-compatible endpoint set in Config (openai_base_url), so results with the default gpt-4.1-mini may differ slightly.
Synthetic test payload:
{"firstname":"Helena","lastname":"Kovac","email":"[email protected]","company":"Example Clinics","website":"https://example.com","jobtitle":"VP Operations","company_size":"450","country":"Germany","budget":"25000","message":"Our leads from Google Ads sit in HubSpot for days before anyone calls. Can we talk this week?"}