Quick overview
This workflow receives agency enquiries via an authenticated webhook, uses OpenAI to extract a structured brief and draft reply (optionally enriching with an approved company homepage), deduplicates by searching HubSpot deals, then creates or updates HubSpot records, saves a Gmail draft, and notifies the owner in Slack.
How it works
- Receives a POST request on an authenticated webhook with lead details (requestId, name, email, company, website, message).
- Validates and normalises the payload, then searches HubSpot Deals for an existing deal with the same deterministic deal name to prevent duplicate processing.
- If the enquiry already exists, returns the existing HubSpot deal ID to the caller without creating a new deal or Gmail draft.
- If the website domain is allowlisted, fetches the company homepage and extracts bounded plain text to use as research evidence.
- Uses OpenAI to extract a structured lead brief and reply draft, then applies deterministic scoring and assigns a HubSpot owner based on budget, service fit, urgency, and verified website evidence (falling back to a manual-review payload if AI fails).
- Upserts the contact in HubSpot, creates an associated HubSpot deal with the qualification details, saves a personalised Gmail reply draft, posts a review notification to Slack, and returns the deal ID and score to the webhook response.
Setup
- Add credentials for Webhook Header Auth, OpenAI, HubSpot (App Token with contacts and deals read/write scopes), Gmail OAuth2, and Slack.
- Update the Settings values for your agency name, supported services, scoring weights, budget threshold/currency, HubSpot owner IDs, pipeline ID and deal stage ID, Slack channel ID, and OpenAI model.
- If you want website enrichment, populate enrichmentAllowedDomains with the exact domains you approve for fetching; leave it as an empty array to skip research.
- Configure your website or form backend to POST JSON fields (requestId, name, email, company, website, message) to the webhook URL and reuse the same requestId for retries so deduplication works.