Intermediate~20 min setupCommunication & CRMVerified April 2026
Slack logo
Zoho CRM logo

How to Send Zoho CRM Deal Stage Updates to Slack with n8n

Fires a formatted Slack message to a channel whenever a Zoho CRM deal moves to a new pipeline stage, including deal name, owner, value, and the stage it moved to.

Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.

Best for

Sales teams of 5–30 reps who need instant Slack alerts when deals progress or stall, without polling Zoho CRM manually.

Not ideal for

Teams that need two-way Slack-to-CRM updates — this is a one-way notification only; use a different workflow for that.

Sync type

real-time

Use case type

notification

Real-World Example

💡

A 12-person SaaS sales team routes all deal stage changes into a #deals Slack channel so the whole team sees wins and stalls as they happen. Before this, reps refreshed Zoho CRM 3–4 times a day and still missed stage changes for 2–3 hours. After setup, a Slack message fires within 30 seconds of any stage move, including deal value and owner name so managers can jump in without opening the CRM.

What Will This Cost?

Drag the slider to your expected monthly volume.

/mo
505005K50K

Each platform counts differently — Zapier: 1 task per trigger. Make: 1 operation per module per record. n8n: 1 execution per run.

Prices shown for annual billing. Based on published pricing as of April 2026.

Estimated ROI

1000

min saved/mo

$583

labor value/mo

Free

no platform cost

Based on ~2 min manual effort per operation at $35/hr fully loaded labor cost.

Implementation

Skip the setup

Import this workflow directly into n8n

Copy the pre-built n8n blueprint and paste it straight into n8n. All modules, filters, and field mappings are already configured — you just need to connect your accounts.

Before You Start

Make sure you have everything ready.

Zoho CRM account with admin access to Setup > Automation (required to create Workflow Rules and Webhooks)
Slack app with chat:write and channels:read OAuth scopes — create one at api.slack.com/apps and install it to your workspace
n8n instance running (cloud at app.n8n.cloud or self-hosted) with a publicly reachable URL so Zoho can POST to it
Zoho CRM Deals module with a Stage field configured — confirm the field name is exactly 'Stage' in the module's field settings
Bot user invited to the target Slack channel with /invite before the workflow fires

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Deal NameDeal_Name
StageStage
OwnerOwner
Deal IDid
4 optional fields▸ show
AmountAmount
Account NameAccount_Name
Close DateClosing_Date
Modified TimeModified_Time

Step-by-Step Setup

1

n8n Canvas > + New Workflow

Create a new workflow in n8n

Open your n8n instance and click the '+ New Workflow' button in the top-right corner of the canvas screen. Give the workflow a clear name like 'Zoho CRM Deal Stage → Slack'. You'll land on a blank canvas with a single node prompt in the center. This is where you'll add the webhook trigger node first.

  1. 1Click '+ New Workflow' in the top-right corner
  2. 2Click the workflow title at the top and rename it to 'Zoho CRM Deal Stage → Slack'
  3. 3Click the '+ Add first step' button in the center of the canvas
What you should see: You should see a blank canvas with the 'Add first step' panel open on the right side.
2

Canvas > Add Node > Webhook

Add a Webhook trigger node

In the node search panel, type 'Webhook' and select the core Webhook node. Set the HTTP Method to POST and leave the path as the auto-generated UUID — you'll copy this URL into Zoho CRM in the next step. Switch the node to 'Test' mode first so you can capture a live payload from Zoho before building the rest of the workflow. The webhook URL will look like https://your-n8n-instance.com/webhook-test/[uuid].

  1. 1Type 'Webhook' in the node search box and select the Webhook node
  2. 2Set HTTP Method to 'POST'
  3. 3Copy the Test URL shown at the top of the node panel
  4. 4Leave Authentication set to 'None' for now
What you should see: The Webhook node appears on the canvas and shows a Test URL and a Production URL. The node displays a 'Waiting for test event' status when you click 'Listen for test event'.
Common mistake — The Test URL and Production URL are different. Zoho CRM will only call the Production URL once you activate the workflow. During setup, paste the Test URL into Zoho — then swap it to the Production URL before going live.
n8n
+
click +
search apps
Slack
SL
Slack
Add a Webhook trigger node
Slack
SL
module added
3

Zoho CRM > Setup > Automation > Actions > Webhooks

Configure Zoho CRM webhook to fire on stage changes

In Zoho CRM, navigate to Setup > Automation > Actions > Webhooks and click '+ New Webhook'. Name it 'n8n Deal Stage Trigger', paste the n8n Test URL into the URL field, and set the method to POST. Under 'Module', select 'Deals'. You'll set the actual trigger condition (stage field change) in the Workflow Rules step, not here — this step just registers the endpoint.

  1. 1Go to Setup > Automation > Actions > Webhooks
  2. 2Click '+ New Webhook'
  3. 3Set Method to POST and paste the n8n Test URL
  4. 4Under 'Module', select 'Deals'
  5. 5Under 'Parameters', add the merge fields: Deal Name, Stage, Amount, Owner, Account Name, Deal ID, Modified Time
  6. 6Click Save
What you should see: The webhook appears in the list with a green Active status and the module listed as 'Deals'.
Common mistake — Zoho CRM sends webhook payloads as form-encoded key-value pairs by default, not JSON. In the webhook config, scroll down to 'Additional Parameters' and set the content type to 'application/json' — otherwise n8n will receive an unparsed string and your field mapping will break.
4

Zoho CRM > Setup > Automation > Workflow Rules > + Create Rule

Create a Workflow Rule in Zoho CRM to fire on stage changes

Still in Zoho CRM, go to Setup > Automation > Workflow Rules and click '+ Create Rule'. Set the module to 'Deals' and the trigger to 'Field Update'. Set the condition to fire when the 'Stage' field is modified. Under Actions, attach the webhook you created in the previous step. This is what actually calls n8n when a deal moves stages — without this rule, the webhook never fires.

  1. 1Click '+ Create Rule' and set Module to 'Deals'
  2. 2Set Rule Trigger to 'Field Update'
  3. 3Under 'Field', select 'Stage' and check 'Any Change'
  4. 4Under Actions > Webhooks, attach the webhook you created in Step 3
  5. 5Click Save and Activate
What you should see: The workflow rule shows as Active and lists your webhook under the Actions column.
Common mistake — If you want stage-specific alerts (e.g., only fire on 'Closed Won'), add a condition in the rule: Stage equals 'Closed Won'. Otherwise the workflow fires on every stage change, including moves backward — which will flood your Slack channel.
5

n8n Canvas > Webhook Node > Listen for test event

Capture a test payload from Zoho CRM

Back in n8n, click your Webhook node and hit 'Listen for test event'. Then go to Zoho CRM and manually edit a test deal — change its Stage field to something different and save. Within a few seconds, n8n should receive the payload and show the incoming fields on the right side of the node. This live payload is what all downstream nodes will reference for field names.

  1. 1Click the Webhook node on the canvas
  2. 2Click 'Listen for test event' in the node panel
  3. 3Switch to Zoho CRM, open a test deal, and change the Stage field
  4. 4Click Save on the deal in Zoho CRM
  5. 5Return to n8n and confirm the payload appeared
What you should see: The Webhook node shows 'Test event received' and displays the incoming JSON fields including Deal_Name, Stage, Amount, Owner, and Modified_Time in the Output panel on the right.
n8n
▶ Run once
executed
Slack
Zoho CRM
Zoho CRM
🔔 notification
received
6

Canvas > + > IF Node

Add an IF node to filter stage changes worth alerting

Click the '+' connector below the Webhook node and add an IF node. Set the condition to check whether the 'Stage' field from the webhook payload is not empty. This prevents the workflow from sending a Slack message if Zoho fires the webhook without a stage value — which can happen when other deal fields are updated simultaneously through Zoho automations. Route the True branch to the next step and leave the False branch empty.

  1. 1Click the '+' below the Webhook node and search for 'IF'
  2. 2Set Condition 1: Value 1 = {{ $json.Stage }}, Operation = 'is not empty'
  3. 3Click 'Add condition' and set Value 1 = {{ $json.Stage }}, Operation = 'is not equal to', Value 2 = ''
  4. 4Connect the True output to the next node
What you should see: The IF node shows two output branches: True and False. The True branch is connected forward; the False branch has no connection.
Common mistake — Filters are the most common place setups break. Double-check the field name and value exactly match what your app sends — a single capital letter difference will block everything.
Slack
SL
trigger
filter
Condition
matches criteria?
yes — passes through
no — skipped
Zoho CRM
ZO
notified
7

Canvas > + > Code Node > JavaScript

Add a Code node to build the Slack message

Click '+' on the True branch of the IF node and add a Code node. Set the language to JavaScript. Write logic here to format the Slack message text, including the deal name, stage, owner, and amount. You can also set an emoji based on the stage — Closed Won gets a trophy, Needs Analysis gets a magnifying glass, and so on. This keeps the Slack message readable without any additional Slack Block Kit setup.

  1. 1Click '+' on the True output of the IF node
  2. 2Search for 'Code' and select the Code node
  3. 3Set Language to 'JavaScript'
  4. 4Paste your formatting logic into the code editor (see Pro Tip below)
  5. 5Click 'Test step' to preview the output
What you should see: The Code node output panel shows a single item with a 'message' field containing a formatted string like ':trophy: *Acme Corp* moved to *Closed Won* — $24,500 | Owner: Jane Smith'.
Common mistake — The Amount field from Zoho comes through as a raw number string like '24500' with no currency symbol or comma formatting. Add Number formatting in the Code node or the Slack message will read '$24500' — jarring in a team channel.

Paste this into the Code node in Step 7. It formats the Amount with commas and a dollar sign, picks an emoji based on the deal stage, and builds a Zoho CRM deep link so team members can click straight into the deal from Slack.

JavaScript — Code Node// n8n Code Node — Deal Stage Slack Message Formatter
▸ Show code
// n8n Code Node — Deal Stage Slack Message Formatter
// Paste this into the Code node between the IF node and the Slack node
const items = $input.all();

... expand to see full code

// n8n Code Node — Deal Stage Slack Message Formatter
// Paste this into the Code node between the IF node and the Slack node

const items = $input.all();

const stageEmojis = {
  'Qualification': ':mag:',
  'Needs Analysis': ':clipboard:',
  'Value Proposition': ':bulb:',
  'Identify Decision Makers': ':busts_in_silhouette:',
  'Perception Analysis': ':bar_chart:',
  'Proposal/Price Quote': ':memo:',
  'Negotiation/Review': ':handshake:',
  'Closed Won': ':trophy:',
  'Closed Lost': ':x:'
};

return items.map(item => {
  const data = item.json;

  const stage = data.Stage || 'Unknown Stage';
  const dealName = data.Deal_Name || 'Unnamed Deal';
  const owner = data.Owner || 'Unassigned';
  const accountName = data.Account_Name || '';
  const dealId = data.id || '';

  // Format amount as currency string
  const rawAmount = parseFloat(data.Amount) || 0;
  const formattedAmount = rawAmount.toLocaleString('en-US', {
    style: 'currency',
    currency: 'USD',
    minimumFractionDigits: 0,
    maximumFractionDigits: 0
  });

  // Pick emoji or default
  const emoji = stageEmojis[stage] || ':arrow_right:';

  // Build Zoho CRM deep link
  const crmBaseUrl = 'https://crm.zoho.com/crm/org/tab/Potentials';
  const dealLink = dealId ? `<${crmBaseUrl}/${dealId}|View Deal>` : '';

  // Build account context string
  const accountStr = accountName ? ` (${accountName})` : '';

  // Compose final message
  const message = `${emoji} *${dealName}*${accountStr} moved to *${stage}* — ${formattedAmount} | Owner: ${owner}${dealLink ? ' | ' + dealLink : ''}`;

  return {
    json: {
      message,
      stage,
      dealName,
      owner,
      formattedAmount
    }
  };
});
message template
🔔 New Record: {{text}} {{user}}
channel: {{channel}}
ts: {{ts}}
#sales
🔔 New Record: Jane Smith
Company: Acme Corp
8

Canvas > + > Slack Node > Message > Send

Add the Slack node and configure the message

Click '+' after the Code node and search for 'Slack'. Select the Slack node and set the Resource to 'Message' and the Operation to 'Send'. Connect your Slack credential (OAuth2 — you'll need the chat:write scope). Set the Channel field to the target channel ID or name (e.g., #deals). In the Text field, reference the formatted message from the Code node: {{ $json.message }}.

  1. 1Click '+' after the Code node and search for 'Slack'
  2. 2Set Resource to 'Message', Operation to 'Send'
  3. 3Click 'Credential for Slack' and connect your Slack OAuth2 app
  4. 4Set Channel to '#deals' or paste the channel ID
  5. 5Set Text to {{ $json.message }}
  6. 6Optionally set Username to 'Deal Bot' and Icon to ':briefcase:'
What you should see: After clicking 'Test step', you should see a Slack message appear in your #deals channel within 5 seconds with the formatted deal update.
Common mistake — Slack requires the channel ID (e.g., C04XXXXXX) if the bot isn't already a member of the channel. If you use the channel name and the bot isn't invited, the node will return a 'channel_not_found' error. Run '/invite @YourBotName' in the Slack channel first.
9

Slack Node > Settings (gear icon) > Error Handling > Continue on Fail

Add error handling with a catch node

Click the three-dot menu on the Slack node and enable 'Continue on Fail'. Then add a second Slack node connected to the error output and configure it to message a private #alerts channel with the error details. This way, failed webhook deliveries don't silently disappear — your team sees the error in Slack rather than missing a deal update entirely.

  1. 1Click the Slack node, then click the Settings tab inside the node panel
  2. 2Toggle 'Continue on Fail' to ON
  3. 3Click '+' on the error output branch
  4. 4Add another Slack node pointing to a #workflow-alerts channel
  5. 5Set Text to 'Deal stage webhook failed: {{ $json.error.message }} for deal {{ $node["Webhook"].json.Deal_Name }}'
What you should see: The canvas shows two Slack nodes — one for the success path and one on the error branch. Both are connected and visible.
10

n8n Canvas > Workflow toggle (top-right) > Active

Activate the workflow and swap to the Production URL

Before activating, go back to your Webhook node and copy the Production URL (not the Test URL). Then go to Zoho CRM > Setup > Automation > Actions > Webhooks, edit the webhook you created in Step 3, and replace the Test URL with the Production URL. Back in n8n, toggle the workflow to Active using the switch in the top-right of the canvas. The workflow now runs on every real deal stage change.

  1. 1Click the Webhook node and copy the Production URL from the node panel
  2. 2Go to Zoho CRM > Setup > Automation > Actions > Webhooks
  3. 3Edit your webhook and replace the URL with the Production URL
  4. 4Save the webhook in Zoho CRM
  5. 5Return to n8n and toggle the workflow switch to Active
What you should see: The workflow toggle shows green/Active in n8n. The next real deal stage change in Zoho CRM fires a Slack message without any manual trigger.
Common mistake — If you forget to swap the URL from Test to Production, Zoho CRM will keep calling the test endpoint which only works when you're manually listening. Your workflow will appear active but silently miss every real event.
11

n8n Left Sidebar > Executions

Test with a live deal stage change

Go to Zoho CRM and move a real (or test) deal from one stage to another. Check your #deals Slack channel within 30 seconds. Then check the n8n Executions panel (left sidebar > Executions) to confirm the run shows as 'Success'. If it failed, click the execution to see exactly which node errored and what the payload looked like.

  1. 1Open Zoho CRM and change a deal's Stage field
  2. 2Check your #deals Slack channel for the notification
  3. 3Click 'Executions' in the n8n left sidebar
  4. 4Find the most recent execution and confirm it shows a green 'Success' badge
  5. 5Click into the execution to inspect each node's input and output data
What you should see: The Executions panel shows a green 'Succeeded' entry with the correct timestamp. The Slack message in #deals displays the deal name, new stage, owner, and formatted dollar amount.

Going live

Production Checklist

Before you turn this on for real, confirm each item.

Troubleshooting

Common errors and how to fix them.

Frequently Asked Questions

Common questions about this workflow.

Analysis

VerdictWhy n8n for this workflow

Use n8n for this if you're self-hosting, you want to avoid per-task pricing at scale, or you need to run custom JavaScript logic before the Slack message fires — like picking emojis by stage, formatting currency, or building deep links into Zoho CRM. n8n also lets you add error routing, conditional branching, and a fallback alert channel without any additional cost. The one case where you'd pick something else: if nobody on your team is comfortable with a webhook URL, a JSON payload, or reading an execution log, Zapier's Zoho CRM + Slack Zap does the same job in about 6 minutes with zero configuration overhead.

Cost

On n8n Cloud, each deal stage change = 1 execution. The Starter plan includes 2,500 executions/month for $20. A sales team closing 80 deals/month across an average of 6 stage changes per deal = 480 executions/month — well inside the free tier if you're on self-hosted, or a fraction of the Starter plan on cloud. Zapier's equivalent (Zap with Zoho CRM trigger + Slack action) costs 2 tasks per run on their paid plans, so 480 events = 960 tasks/month — that's $29.99/month on the Professional plan. n8n self-hosted is $0 for the same volume. Even on n8n Cloud, you're saving roughly $10/month at this volume.

Tradeoffs

Zapier has a native Zoho CRM 'Updated Deal Stage' trigger that requires zero webhook configuration — it polls every 15 minutes, which is too slow for real-time alerts but dead simple to set up. Make's Zoho CRM module has a Watch Records trigger with a 5-minute poll interval and a cleaner field-mapping UI than n8n, which matters if your team changes the workflow frequently. Power Automate has a Zoho CRM connector but it's a premium connector ($15/user/month add-on) and the Zoho trigger options are limited compared to using a direct webhook. Pipedream's Zoho CRM source can use webhooks and has built-in TypeScript support, making it competitive with n8n for developers — the difference is Pipedream charges per invocation at scale while n8n self-hosted doesn't. n8n wins here if you want real-time delivery, custom code, and cost control in one place.

Three things you'll hit after going live. First: Zoho CRM's webhook payload doesn't include the previous stage value — only the current one. If you want to show 'moved FROM Qualification TO Proposal', you'd need to store the last known stage in n8n's static data or a separate table and compare on each run. Second: Zoho's webhook fires on any field update to the deal record if your Workflow Rule condition isn't tight enough — a rep updating a phone number will trigger your Slack message if the rule is set to 'Any Field' instead of 'Stage Field'. Double-check the rule condition after go-live. Third: The Amount field arrives as a bare number string ('48000') with no currency symbol or formatting. If your team operates in multiple currencies, the Zoho payload also doesn't include the currency code — you'll need to hardcode your base currency in the Code node or pull it from a separate Zoho API call.

Ideas for what to build next

  • Stage-specific Slack channelsRoute different stage changes to different channels — Closed Won goes to #wins, Closed Lost goes to #postmortem, early stages go to #pipeline. Add a Switch node after the IF node to branch by stage value.
  • Daily deal pipeline digestAdd a second workflow with a Schedule trigger that queries Zoho CRM at 8am each day for all deals modified in the last 24 hours and posts a summary to #deals. Pairs with this real-time workflow so the team gets both instant alerts and a morning recap.
  • Slack reply triggers Zoho CRM noteBuild a reverse workflow where a reply to a deal stage Slack message (using Slack's thread reply event) creates a note on the deal in Zoho CRM. Requires the Slack Events API and a second n8n workflow with a Zoho CRM 'Create Note' node.

Related guides

Was this guide helpful?
Slack + Zoho CRM overviewn8n profile →