What this workflow does
- Nightly at 1am starts the run.
- Get open and recently closed deals pages through the HubSpot deal search: every open deal, plus deals closed in the last 30 days, with stage, probability, amount, dates, owner and last activity.
- Build snapshot rows flattens all pages into one batch and removes duplicates.
- Write snapshot upserts the batch into
deal_snapshots, keyed on date and deal ID, so reruns are safe. - Is it Monday? lets the snapshot run every night but only reports once a week.
- Compute weekly movement is one SQL query. It compares the newest snapshot with the one from at least seven days earlier. Each deal is labeled new, advanced, moved back, slipped (close date pushed), won, lost, or missing (merged or deleted). It also computes open and weighted pipeline, 30-day wins and losses, and stale deals.
- Format report payload turns every figure into a display string and builds the plain table.
- Write narrative with Claude asks for a headline and five to eight sentences, using only the strings in the payload. The output follows a strict JSON schema.
- Check every number extracts each number from the commentary and confirms it appears in the payload. A failed check, a refusal, a truncated reply or an API error means the table posts without commentary and an alert goes out.
- Post pipeline report sends the result to Slack. Alert: report needs attention receives anything that failed.
Before you import
- A current n8n version, cloud or self-hosted.
- A HubSpot private app token with
crm.objects.deals.read. - A Postgres database (the smallest hosted tier is fine).
- An Anthropic API key and a Slack app that can post.
Setup
- Import the JSON and run the
CREATE TABLEstatement from the yellow note. - Attach credentials: HubSpot Service Key on the search node, Postgres on both Postgres nodes, Anthropic on the Claude node, Slack on both Slack nodes.
- Replace
REPLACE_WITH_REPORT_CHANNELandREPLACE_WITH_ALERTS_CHANNEL. - If you run several pipelines, add a
pipelinefilter to the search body, or group the SQL by pipeline. - Check that stage probabilities increase through your stages, because “advanced” and “moved back” rely on them.
- Set your instance time zone so “Monday” and “1am” mean what you expect.
Test it
Run the workflow manually once to create today’s snapshot. To test the weekly report without waiting a week, copy today’s rows to a date eight days back in Postgres, then edit a few of them (lower a probability, push a close date). Temporarily set the Monday check to true and run again. The Slack post should show those deals as advanced or slipped. Then tell Claude in the system prompt to invent a growth percentage and confirm the table posts without commentary.
Make it production-ready
- Run in parallel first. Send the report only to the sales leader for two weeks and reconcile it against the manual version.
- Map stages by ID. Add a stage lookup table so renamed stages keep their history and labels read well.
- Error workflow. Add an n8n error workflow for failures before the report step, such as an expired HubSpot token.
- Rate limits. Large first runs can hit HubSpot search limits; the pagination waits 250 ms between pages and stops at 100 pages.
- Audit trail. Store each posted report in a table so you can show what leaders saw on a given Monday.
The pipeline reporting guide explains the definitions to agree on before building. If you want this built against your CRM, start here.