HubSpot + n8n + Claude: a dispatch workflow for support teams, step by step
A step-by-step dispatch workflow for support teams using HubSpot, n8n and Claude: trigger, classifier, quality gate, ticket creation and Slack posting.
This is the practical version. If you have a support team, a HubSpot account and a shared inbox, here is how I would wire a dispatch workflow with n8n for the plumbing and Claude for the judgement. It is the same shape as the one I run in production, described at a higher level in the post on cutting handling time.
The shape of the workflow
Five steps, each one a node or a small group of nodes in n8n:
- Trigger: a message arrives.
- Enrich: look up the customer and any open tickets.
- Classify: Claude returns structured labels and a confidence score.
- Gate: checks decide continue or hold.
- Act: create the HubSpot ticket, post to Slack, queue the reply for review.
I keep the logic in n8n and the judgement in Claude. n8n is good at moving data, retrying, and branching. Claude is good at reading messy human text. Mixing the two jobs in one place is how workflows become impossible to debug.
Step 1: the trigger
Pick one entry point per channel and normalise it. A WhatsApp Business webhook, a Slack event and an email forwarder all produce different payloads. The first node in each branch should convert the payload to a single shape: channel, sender, text, received_at, thread_id. Everything after that works on one format.
A trap I fell into early: triggering on every Slack message in a busy channel, including the bot's own posts. Add a filter at the start that drops anything from your own automation, or you will build a loop.
Step 2: enrich before you classify
Give the model what a human would look up. Query HubSpot for the contact by phone or email, and return the customer's tier, their last few tickets, and whether a ticket for the same order is already open. This context does two things: it makes the classification better, and it feeds the duplicate check later.
Step 3: what the classifier sees
The prompt has three parts: a fixed list of allowed labels with one-line definitions, the enrichment data, and the message. The instruction asks for strict JSON with intent, priority, team, summary and confidence. In n8n, parse the JSON in a code node and fail the item if it does not parse. A parse failure should go to the human queue, never to a default label.
Keep the label list short. If two labels would make a human pause, merge them until the data says you need them apart.
Step 4: the gate
A single IF-style branch is not enough. I run these checks in order:
- Confidence at or above 0.90.
- No sensitive personal data in the text that will be posted to a shared channel.
- No open ticket for the same customer and order. If there is one, add the message as a note on that ticket and stop.
- Label is in the allowed list. Models occasionally invent a plausible label, and the check costs nothing.
Failures go to a review queue, which in my setup is a HubSpot view plus a Slack post to a small review channel. More on this in the quality gate post.
Step 5: act
For items that pass, create the HubSpot ticket through the API node with the pipeline, owner, priority, and a deadline derived from priority. Then post to the team's Slack channel with the summary, the customer tier, and the ticket link. Store the ticket id back on the original message record so you can trace any item end to end.
Owner assignment deserves care. I use a simple rule: the on-shift person for that team, falling back to the team lead. A ticket with no owner is the same failure as before the automation existed.
A worked example
Illustrative input from Slack, posted by a colleague in a shared channel:
Customer on order 4821 says the rider never collected the bag, she is VIP, please check
The enrichment finds a gold-tier contact with no open ticket for this order. Claude returns intent delivery, subtype not_collected, priority high, team delivery, confidence 0.95. All four gate checks pass. A ticket is created with an owner from the delivery on-shift list. The delivery channel gets a post: "VIP, order 4821, bag not collected, owner assigned, ticket linked." Nobody had to read it first, sort it, or copy it.
What went wrong the first time
Three mistakes, all avoidable:
- No error branch. When the HubSpot API rate-limited a burst, items silently disappeared. Every node that can fail now has a path that posts to an alerts channel with the item attached.
- Prompt edits in production. I changed the label list on a live workflow and could not tell later which version produced which result. Prompts now live in a versioned place, and each item stores the version it was processed with.
- No idempotency. A retry created two tickets. The message id is now a key, and the create step checks it first.
Trade-offs
- Self-hosting n8n gives control and cost certainty, and it makes you responsible for uptime and updates. I wrote about this choice in Zapier vs n8n vs Make.
- Enrichment calls slow every item down slightly. For a support queue that is acceptable. For anything that needs a reply in seconds, cache the lookups.
- More gate checks mean fewer bad outcomes and a longer human queue. Tune with data from the daily sample.
What I would build for your team
I would start from your actual inbox: the three busiest intents, the owners, and the channel each should land in. I would build the smallest version of these five steps with the gate in place, run it beside your current process, and show you the time saved as a number before anything is switched off. Everything is documented in a runbook, so your team can change a label without calling me.
Email: kodirovrukhillo@gmail.com