When your pipeline is full, the easiest deals to lose are the ones that go quiet. Picture this: an automotive dealership quotes a 2025 Honda CR-V to a hot lead. The client loves the car but wants to “think about the monthly payment.” A week passes, then two. The salesperson gets busy, forgets to follow up, and the buyer walks into a competitor’s showroom instead. This automation prevents exactly that: every morning it scans Salesforce for stalled opportunities, pulls real context (notes, contact, owner), and automatically sends a personalized follow-up email, posts a Slack reminder, and creates a Salesforce Task so the deal doesn’t die in silence.
Download Here: https://www.crmaiinsight.com/flows/stale_deals_alert.json


What this workflow does (high-level)

This n8n template turns “I’ll follow up later” into a reliable daily habit:

  1. Every morning at 8:00 – n8n runs automatically.
  2. Finds ‘stale’ Opportunities – based on Stage_Unchanged_Days__c and excluding Closed Won / Closed Lost.
  3. Loads full Opportunity details from Salesforce.
  4. Asks OpenAI (GPT-5.1 in this case) to:
    • Query Salesforce Notes, primary Contact, and Owner using a tool (query_soql)
    • Draft:
      • A follow-up email to the client
      • A short SMS template
      • A Slack summary for the internal team
      • A Task payload for Salesforce
  5. n8n then:
    • Sends the email (SMTP)
    • Posts the Slack message (sales channel)
    • Creates the Task in Salesforce via REST API

End result: no stale deal is left without a nudge and every follow-up is recorded as a Task.


Prerequisites

You’ll need:

  • A Salesforce org with:
    • Custom field Stage_Unchanged_Days__c (Formula Number) on Opportunity
    • Opportunity stages including Closed Won and Closed Lost
  • Salesforce OAuth2 credentials in n8n (salesforceOAuth2Api)
  • OpenAI credentials (openAiApi)
  • SMTP credentials for outbound email
  • Slack app / bot + slackApi credentials
  • n8n instance (self-hosted or cloud)

Recommended Stage_Unchanged_Days__c formula

In Salesforce (Setup → Object Manager → Opportunity → Fields & Relationships):

  • Field Label: Stage Unchanged Days
  • Data Type: Formula (Number, 0 decimal places)
  • Formula:
IF(
  ISBLANK(LastStageChangeDate),
  TODAY() - DATEVALUE(CreatedDate),
  TODAY() - DATEVALUE(LastStageChangeDate)
)

This is what the flow uses to detect stale deals.


Node-by-Node Walkthrough

Below is the flow you shared, with names aligned to the blog so someone can follow your template screenshot by screenshot.

1. Schedule Trigger – run every morning

Node: Schedule Trigger

  • Runs daily at 08:00.
  • Kicks off the entire stale-deal scan.

2. Edit Fields – set the stale days threshold

Node: Edit Fields (Set)

  • Sets stale_days (Number) to your chosen threshold (e.g., 7, 14).
  • Makes it easy to change the policy in one place instead of editing SOQL.
stale_days = 0   // For testing; change to 7 or 14 in production


3. Perform a query – find stale Opportunities

Node: Perform a query (Salesforce → resource: search)

SOQL:

Select id
from opportunity
where Stage_Unchanged_Days__c = {{ $json.stale_days }}
  And StageName Not In ('Closed Won', 'Closed Lost')

  • Returns only open Opportunities that have been in the same stage for exactly stale_days days.
  • This defines what counts as “stale”.

4. Get an opportunity – load full deal context

Node: Get an opportunity (Salesforce → resource: opportunity, operation: get)

  • OpportunityId = {{ $json.Id }} from the search node.
  • Fetches full fields:
    • Name, AccountId, StageName, Stage_Unchanged_Days__c
    • Amount, CloseDate, Type, LeadSource
    • OwnerId, IsClosed, IsWon, etc.

This gives the AI enough context to write deal-specific follow-up messages.


5. query_soql – give the AI live access to Salesforce

Node: query_soql (HTTP Request Tool)

  • URL:
    https://<yourInstance>.my.salesforce.com/services/data/v64.0/query/
  • Auth: salesforceOAuth2Api
  • Query parameter:
={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters0_Value', ``, 'string') }}

In the Message a model node, this is described as a tool:

  • query_soql(soql: string)
  • Used by the model to run SOQL queries, for example:
    • Notes on the Opportunity
    • Primary Contact on the Account
    • Owner (User) record

6. Message a model – the AI “brain”

Node: Message a model (OpenAI / LangChain)

  • Model: gpt-5.1
  • System prompt (you’ve already written) includes:
    • Detailed instructions on:
      • Role: Salesforce Sales Follow-Up Assistant
      • Input: full Opportunity JSON ({{ JSON.stringify($json) }})
      • How to call query_soql three times:
        • Notes
        • Contact
        • Owner
    • Communication logic for Open / Closed Won / Closed Lost
    • Style guidelines for:
      • Email
      • SMS
      • Slack message
    • Instructions to construct:
      • email
      • sms
      • slack
      • task + task.api_body

The model responds with one JSON object in the exact schema you defined.


7. Parse JSON – make the AI result usable

Node: Parse JSON (Code)

return JSON.parse($input.first().json.output[0].content[0].text)

  • Converts the model’s raw text into a structured object.
  • After this node, you can access:
    • email.to, email.subject, email.body
    • sms.to, sms.body
    • slack.message
    • task.api_body.Subject, task.api_body.OwnerId, etc.

8. Send Email SMTP Customer – contact the client

Node: Send Email SMTP Customer (Email Send)

  • From: =le.nguyen@crmaiinsight.com (or your address)
  • To: ={{ $json.email.to }}
  • Subject: ={{ $json.email.subject }}
  • Body (text): ={{ $json.email.body }}

The email body is already formatted with \n\n for paragraphs, following your style guidelines (friendly, concise, value-driven).


9. Send Message To Internal Team – keep sales in the loop

Node: Send Message To Internal Team (Slack)

  • Channel: your sales / deals channel
  • Text: ={{ $('Parse JSON').item.json.slack.message }}

The Slack message usually includes:

  • Opportunity name, Stage, Amount, Close Date, Stage_Unchanged_Days__c
  • Contact / Account name (if available)
  • Notes summary + follow-up angle (“pricing concern”, “waiting on contract”, etc.)
  • Recommended next internal action (“Call Alex today”, “Review revised finance options”, etc.)

10. Create Task – record the follow-up in Salesforce

Node: Create Task (HTTP Request)

  • Method: POST
  • URL:
    https://<yourInstance>.my.salesforce.com/services/data/v60.0/sobjects/Task
  • Auth: salesforceOAuth2Api
  • JSON Body: ={{ $json.task.api_body }}

The task.api_body object generated by the AI includes:

  • Subject – e.g. “Follow up on stalled opportunity – 2025 Honda CR-V EX-L – Alex Tran”
  • Description – why the task was created, key note highlights, and the gist of email/SMS
  • Status"Not Started"
  • Priority"Normal" or "High"
  • OwnerId – Opportunity Owner or Owner.Id
  • WhatId – Opportunity Id

Now every stale deal has a Task, giving managers visibility and reps a clear to-do.


Setup & Testing Checklist

Use this as a quick-start for someone importing your flow:

  1. Create Stage_Unchanged_Days__c on Opportunity
    • Use the formula above.
  2. Configure credentials in n8n
    • Salesforce OAuth2 on all Salesforce / HTTP Request nodes
    • OpenAI on Message a model
    • SMTP on Send Email SMTP Customer
    • Slack API on Send Message To Internal Team
  3. Set your real stale_days threshold in Edit Fields (e.g., 7 or 14).
  4. Disable the Schedule and run manually first:
    • Check the AI output in Message a model and Parse JSON
    • Verify email + Slack content
    • Confirm Tasks are created correctly in Salesforce
  5. When happy, enable the Schedule Trigger and let it run daily.

How this helps real businesses (beyond the demo story)

Back to that car dealership example: instead of relying on each rep’s memory, the system now:

  • Spots deals that have stalled for 7+ days
  • Reminds the rep in Slack with rich context (“customer concerned about payment; asked for revised quote”)
  • Sends a friendly, non-pushy email to the client
  • Logs a Task so a manager can see if follow-up actually happens

You can use the same pattern for:

  • B2B SaaS trials that go quiet after demo
  • Enterprise RFPs stuck waiting on legal
  • Service quotes (insurance, energy, consulting) where clients “need to think about it”

Anywhere deals age silently, this flow turns that into a structured, consistent follow-up process.


Want a fully Salesforce-native (Agentforce) version?

This article focuses on n8n + OpenAI + Salesforce—great when you want a flexible, multi-system automation layer.

If you prefer a 100% Salesforce Agentforce solution (using:

  • Agentforce prompts for the messaging,
  • Flow / Orchestration for stale-deal detection and Task creation,
  • Native Slack / email actions inside Salesforce),

there is also an Agentforce-native version of this “Stale Deals Alert + Auto Task” pattern.

👉 If you’d like the Agentforce-only design and prompt, just request it and I can share that version too.