Send a Slack alert when a Salesforce deal changes stage using n8n
Install this workflow
Download the n8n workflow JSON and import it into your n8n instance.
sf-deal-stage-alert.n8n.jsonPrerequisites
- n8n instance (cloud or self-hosted)
- Salesforce Connected App with OAuth credentials (Client ID and Client Secret)
- Slack app with Bot Token (
chat:writescope) - n8n credentials configured for both Salesforce and Slack
Why n8n?
n8n gives you more formatting control than Salesforce's native Send Slack Message action. With n8n, you can build full Block Kit messages with sections, context blocks, and rich formatting — the native action is limited to plain text. Self-hosted n8n is free with unlimited executions, so there's no per-alert cost.
The trade-off is that n8n uses polling instead of real-time triggers. The Salesforce Trigger node checks for changes every 1-5 minutes depending on your polling interval. If you need alerts within seconds, use Salesforce Flow Builder instead. But for most teams, a 1-minute delay is acceptable.
How it works
- Salesforce Trigger node polls for updated Opportunities at a set interval (default: every minute)
- IF node filters for actual stage changes since the trigger fires on any Opportunity update
- Salesforce/HTTP node fetches the full Opportunity record with account and owner details via SOQL
- Slack node posts a Block Kit message with deal name, amount, stage, account, owner, and a direct Salesforce link
Step 1: Create a Salesforce Connected App
Before configuring n8n, you need a Connected App in Salesforce for OAuth:
- In Salesforce, go to Setup → App Manager → New Connected App
- Fill in the basics (App Name, Contact Email)
- Check Enable OAuth Settings
- Set Callback URL to your n8n OAuth callback (e.g.,
https://your-n8n.com/rest/oauth2-credential/callback) - Add OAuth scopes:
Full access (full)or at minimumAccess and manage your data (api)andPerform requests on your behalf at any time (refresh_token, offline_access) - Save and wait 2–10 minutes for the Connected App to propagate
- Copy the Consumer Key (Client ID) and Consumer Secret (Client Secret)
In n8n, go to Credentials → New → Salesforce OAuth2 API and enter the Client ID, Client Secret, and your Salesforce instance URL.
Step 2: Add a Salesforce Trigger node
Create a new workflow and add a Salesforce Trigger node:
- Authentication: Select your Salesforce OAuth2 credential
- Resource: Opportunity
- Event: Updated
The Salesforce Trigger node in n8n uses polling, not push webhooks. Set the polling interval to 1 minute for near-real-time alerts. On n8n Cloud, the minimum interval depends on your plan.
Step 3: Add an IF node to filter stage changes
The trigger fires on any Opportunity update. Add an IF node to check if the stage actually changed:
- Condition:
{{ $json.StageName }}is not empty
For more precise filtering, you can check against specific stages:
- Condition:
{{ $json.StageName }}is one ofNegotiation/Review,Closed Won,Closed Lost
Step 4: Fetch full Opportunity details
The trigger may not include all fields you need. Add a Salesforce node to query the full record:
- Resource: Opportunity
- Operation: Get
- Opportunity ID:
{{ $json.Id }}
Or use a Salesforce node with a custom SOQL query for richer data:
- Operation: Custom API Call
- Method: GET
- Endpoint:
/services/data/v59.0/query - Query Parameters:
q= the SOQL below
SELECT Id, Name, Amount, StageName, Account.Name, Owner.Name,
LastModifiedDate
FROM Opportunity
WHERE Id = '006XXXXXXXXXXXXXXX'Replace the hardcoded ID with the expression {{ $json.Id }} in your node configuration.
Step 5: Send Slack notification
Add a Slack node:
- Resource: Message
- Operation: Send
- Channel:
#sales-pipeline(or your deals channel) - Message Type: Block Kit
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "🔄 *Deal Stage Changed*\n*{{ $json.Name }}* moved to *{{ $json.StageName }}*\nAmount: ${{ $json.Amount }}\nAccount: {{ $json.Account.Name }}\nOwner: {{ $json.Owner.Name }}"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "<https://YOUR_INSTANCE.my.salesforce.com/{{ $json.Id }}|View in Salesforce>"
}
]
}
]
}Replace YOUR_INSTANCE with your Salesforce org's subdomain.
n8n's Slack node expects the full blocks wrapper object. If you pass just the array without the outer object, blocks are silently ignored and only the notification text shows.
Step 6: Activate
- Click Execute Workflow to test with a real Opportunity stage change
- Verify the Slack message appears with correct deal info
- Toggle the workflow to Active
Troubleshooting
Common questions
How often does n8n poll Salesforce for changes?
By default, every 1 minute on n8n Cloud (depends on plan). Self-hosted n8n supports custom intervals down to seconds, though 1-minute polling is recommended to avoid Salesforce API rate limits.
Does each polled record count as a separate execution?
No. Each poll cycle is 1 execution, regardless of how many Opportunities were updated. If 10 deals change stage in the same minute, it's still 1 execution (though the downstream nodes run for each record).
Can I detect the previous stage value?
Not directly from the Salesforce Trigger. The trigger payload includes the current field values, not the previous ones. To get the previous stage, query OpportunityFieldHistory in a follow-up SOQL query, or store the last-seen stage in n8n's static data using $getWorkflowStaticData('global').
Cost
- n8n Cloud Starter: $24/mo for 2,500 executions. Each poll interval = 1 execution (regardless of how many records changed).
- Self-hosted: Free. Unlimited executions.
Looking to scale your AI operations?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.