See llms.txt for all machine-readable content.

Back to Templates

Score and route website leads with OpenAI and HubSpot

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

  1. Receives a new lead submission via a POST webhook.
  2. Validates and pre-screens the lead details (especially email domain and message content) to flag spam, disposable emails, and other risk signals.
  3. Searches HubSpot for an existing contact by email to preserve the current owner when a match is found.
  4. Sends the lead details and message to OpenAI Chat Completions to return a JSON classification for intent, urgency, and a short summary.
  5. 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.
  6. 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.
  7. 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

  1. 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.
  2. Add an OpenAI credential and select it on the "AI: read the message" node.
  3. 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.
  4. 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.
  5. 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?"}