

How to Send Zoho CRM Lost Deals to Slack with Pipedream
When a deal is marked Lost in Zoho CRM, Pipedream instantly posts the deal name, loss reason, and competitor data to a Slack management channel via webhook.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.
Best for
Sales managers at 10–100 person companies who need instant visibility into lost deals without logging into Zoho CRM throughout the day.
Not ideal for
Teams that need to log a response back into Zoho CRM after a loss — that requires a two-way sync with additional steps.
Sync type
real-timeUse case type
notificationReal-World Example
A 22-person B2B SaaS sales team uses this to post every lost deal to #revenue-alerts in Slack the moment a rep marks it Lost in Zoho CRM. Before this, the VP of Sales reviewed a Monday morning report and saw competitor names 5–7 days after the loss happened. Now they spot competitor patterns the same day and can adjust talk tracks within hours.
What Will This Cost?
Drag the slider to your expected monthly volume.
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
Import this workflow directly into Pipedream
Copy the pre-built Pipedream blueprint and paste it straight into Pipedream. 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.
Field Mapping
Map these fields between your apps.
| Field | API Name | |
|---|---|---|
| Required | ||
| Deal Name | Deal_Name | |
| Stage | Stage | |
| Loss Reason | Loss_Reason | |
| Deal Amount | Amount | |
| Account Name | Account_Name | |
| Deal Owner | Owner.name | |
3 optional fields▸ show
| Competitor | Competitor |
| Closing Date | Closing_Date |
| Lead Source | Lead_Source |
Step-by-Step Setup
pipedream.com > Dashboard > New Workflow
Create a new Pipedream Workflow
Go to pipedream.com and sign in. Click 'New Workflow' in the top-right corner of the dashboard. You'll land on the workflow canvas with an empty trigger slot at the top. Give the workflow a name — something like 'Zoho Lost Deal → Slack Alert' — by clicking the pencil icon next to the default title. This name appears in your Pipedream dashboard and in error notification emails.
- 1Sign in at pipedream.com
- 2Click the blue 'New Workflow' button in the top-right
- 3Click the pencil icon next to the default workflow name
- 4Type 'Zoho Lost Deal → Slack Alert' and press Enter
Workflow Canvas > Trigger > Search Apps > Zoho CRM > New or Updated Module
Configure the Zoho CRM Webhook Trigger
Click the trigger block and search for 'Zoho CRM' in the app search bar. Select the 'New or Updated Module' event — this fires whenever a record changes in any Zoho CRM module. Choose 'Deals' as the module. Pipedream will generate a unique webhook URL for this trigger immediately. Copy that URL — you'll need it in Zoho CRM in the next step.
- 1Click the empty trigger block on the canvas
- 2Type 'Zoho CRM' in the search box
- 3Select 'Zoho CRM' from the results
- 4Choose 'New or Updated Module' as the trigger event
- 5Set Module to 'Deals'
- 6Copy the generated webhook URL from the trigger panel
Trigger Panel > Connect Account > Zoho CRM OAuth Popup
Connect Your Zoho CRM Account
In the trigger configuration panel, click 'Connect Account' under the Zoho CRM section. A popup will appear asking you to authorize Pipedream to access your Zoho CRM org. Sign in with your Zoho credentials and click 'Accept'. Pipedream stores the OAuth token in Connected Accounts — you won't need to re-enter credentials for future Zoho steps in any workflow.
- 1Click 'Connect Account' in the Zoho CRM trigger panel
- 2Sign in with your Zoho CRM admin credentials in the popup
- 3Click 'Accept' to grant Pipedream read access
- 4Select the connected account from the dropdown if prompted
Zoho CRM > Setup > Developer Space > Webhooks > + New Webhook
Register the Webhook in Zoho CRM
Open Zoho CRM in a new browser tab. Navigate to Setup > Developer Space > Webhooks and click '+ New Webhook'. Give it a name like 'Lost Deal Pipedream Alert'. Paste the Pipedream webhook URL from Step 2 into the URL field. Set the method to POST and the format to JSON. Under Modules, select 'Deals' and set the trigger event to 'Edit'. This fires the webhook every time a deal record is saved.
- 1In Zoho CRM, go to Setup > Developer Space > Webhooks
- 2Click '+ New Webhook'
- 3Enter a name: 'Lost Deal Pipedream Alert'
- 4Paste the Pipedream URL into the Notify URL field
- 5Set Method to POST, Format to JSON
- 6Set Module to Deals, Trigger to Edit
- 7Click Save
Zoho CRM > Any Deal Record > Edit > Stage: Lost > Save | Pipedream Trigger Panel > Events tab
Send a Test Event to Capture the Payload
Go back to Pipedream. The trigger is listening. In Zoho CRM, open any existing deal, change the Stage field to 'Lost', fill in a Loss Reason and Competitor if your fields support it, and click Save. Pipedream will capture this event within 2–5 seconds. Click on the captured event in the trigger panel to see the full JSON payload. Expand the body to confirm all the fields you added in Step 4 are present.
- 1Open a test deal in Zoho CRM
- 2Change Stage to 'Lost', enter a Loss Reason and Competitor
- 3Click Save in Zoho CRM
- 4Switch to Pipedream and click the 'Events' tab in the trigger panel
- 5Click the captured event to expand the JSON payload
- 6Verify Deal_Name, Stage, Loss_Reason, Competitor, Amount, and Owner are all present
Workflow Canvas > + Add Step > Run Node.js Code
Add a Code Step to Filter for Lost Deals Only
Click '+ Add Step' below the trigger and choose 'Run Node.js code'. This step checks whether the incoming deal's Stage is actually 'Lost' before continuing. Without this filter, the workflow runs on every deal edit — including stage changes like Proposal to Negotiation — which means noisy, incorrect Slack alerts. The code uses $.flow.exit() to halt execution for non-lost deals without marking the run as an error.
- 1Click '+ Add Step' below the trigger block
- 2Select 'Run Node.js Code'
- 3Paste the filter code into the code editor
- 4Click 'Test' to verify it passes for Stage = Lost and exits for other stages
This code combines the filter, deduplication check, and Slack Block Kit message formatting into two code steps. Paste the filter/dedup block into Step 6 and the formatter block into Step 7 on your Pipedream workflow canvas. The deduplication uses Pipedream's built-in key-value data store to prevent duplicate Slack alerts when Zoho fires the webhook twice for the same deal save.
JavaScript — Code Step// STEP 6: Filter for Lost deals + deduplicate using Pipedream Data Store▸ Show code
// STEP 6: Filter for Lost deals + deduplicate using Pipedream Data Store
import { axios } from '@pipedream/platform';
export default defineComponent({... expand to see full code
// STEP 6: Filter for Lost deals + deduplicate using Pipedream Data Store
import { axios } from '@pipedream/platform';
export default defineComponent({
props: {
data: { type: 'data_store' },
},
async run({ steps, $ }) {
const payload = steps.trigger.event.body;
const deal = Array.isArray(payload.Deals) ? payload.Deals[0] : payload;
// Only continue if Stage is Lost
const stage = deal.Stage ?? '';
if (stage !== 'Lost') {
$.flow.exit('Deal stage is not Lost — skipping');
}
// Deduplicate: skip if same deal was processed in the last 60 seconds
const dealId = deal.id ?? deal.Deal_Name;
const lastSeen = await this.data.get(dealId);
const now = Date.now();
if (lastSeen && now - lastSeen < 60000) {
$.flow.exit(`Duplicate event for deal ${dealId} — skipping`);
}
await this.data.set(dealId, now);
// Export clean deal object for next step
return {
dealName: deal.Deal_Name ?? 'Unnamed Deal',
stage: deal.Stage,
lossReason: deal.Loss_Reason ?? 'Not specified',
competitor: deal.Competitor ?? 'Unknown',
amount: deal.Amount ? `$${Number(deal.Amount).toLocaleString()}` : 'N/A',
accountName: deal.Account_Name ?? 'Unknown Account',
ownerName: deal.Owner?.name ?? 'Unknown Owner',
closingDate: deal.Closing_Date ?? 'N/A',
dealId,
};
},
});
// STEP 7: Format Slack Block Kit message
export default defineComponent({
async run({ steps, $ }) {
const d = steps.filter_lost_deal.$return_value;
const blocks = [
{
type: 'header',
text: {
type: 'plain_text',
text: `🔴 Deal Lost: ${d.dealName}`,
emoji: true,
},
},
{
type: 'section',
fields: [
{ type: 'mrkdwn', text: `*Account:*\n${d.accountName}` },
{ type: 'mrkdwn', text: `*Amount:*\n${d.amount}` },
{ type: 'mrkdwn', text: `*Loss Reason:*\n${d.lossReason}` },
{ type: 'mrkdwn', text: `*Competitor:*\n${d.competitor}` },
{ type: 'mrkdwn', text: `*Owner:*\n${d.ownerName}` },
{ type: 'mrkdwn', text: `*Expected Close:*\n${d.closingDate}` },
],
},
{
type: 'divider',
},
{
type: 'context',
elements: [
{
type: 'mrkdwn',
text: `Deal ID: ${d.dealId} • Logged via Pipedream`,
},
],
},
];
return { blocks };
},
});Workflow Canvas > + Add Step > Run Node.js Code
Add a Code Step to Format the Slack Message
Click '+ Add Step' and add another Node.js code step. This step pulls the deal fields from the Zoho webhook payload and constructs a structured Slack Block Kit message. Using Block Kit instead of a plain text message gives you bold deal names, organized sections for loss reason and competitor, and an amount field — all scannable at a glance in Slack. The code exports the formatted blocks object for the next step to consume.
- 1Click '+ Add Step' below the filter step
- 2Select 'Run Node.js Code'
- 3Paste the Slack Block Kit formatting code into the editor
- 4Click 'Test' and check the exported 'blocks' array in the step output
This code combines the filter, deduplication check, and Slack Block Kit message formatting into two code steps. Paste the filter/dedup block into Step 6 and the formatter block into Step 7 on your Pipedream workflow canvas. The deduplication uses Pipedream's built-in key-value data store to prevent duplicate Slack alerts when Zoho fires the webhook twice for the same deal save.
JavaScript — Code Step// STEP 6: Filter for Lost deals + deduplicate using Pipedream Data Store▸ Show code
// STEP 6: Filter for Lost deals + deduplicate using Pipedream Data Store
import { axios } from '@pipedream/platform';
export default defineComponent({... expand to see full code
// STEP 6: Filter for Lost deals + deduplicate using Pipedream Data Store
import { axios } from '@pipedream/platform';
export default defineComponent({
props: {
data: { type: 'data_store' },
},
async run({ steps, $ }) {
const payload = steps.trigger.event.body;
const deal = Array.isArray(payload.Deals) ? payload.Deals[0] : payload;
// Only continue if Stage is Lost
const stage = deal.Stage ?? '';
if (stage !== 'Lost') {
$.flow.exit('Deal stage is not Lost — skipping');
}
// Deduplicate: skip if same deal was processed in the last 60 seconds
const dealId = deal.id ?? deal.Deal_Name;
const lastSeen = await this.data.get(dealId);
const now = Date.now();
if (lastSeen && now - lastSeen < 60000) {
$.flow.exit(`Duplicate event for deal ${dealId} — skipping`);
}
await this.data.set(dealId, now);
// Export clean deal object for next step
return {
dealName: deal.Deal_Name ?? 'Unnamed Deal',
stage: deal.Stage,
lossReason: deal.Loss_Reason ?? 'Not specified',
competitor: deal.Competitor ?? 'Unknown',
amount: deal.Amount ? `$${Number(deal.Amount).toLocaleString()}` : 'N/A',
accountName: deal.Account_Name ?? 'Unknown Account',
ownerName: deal.Owner?.name ?? 'Unknown Owner',
closingDate: deal.Closing_Date ?? 'N/A',
dealId,
};
},
});
// STEP 7: Format Slack Block Kit message
export default defineComponent({
async run({ steps, $ }) {
const d = steps.filter_lost_deal.$return_value;
const blocks = [
{
type: 'header',
text: {
type: 'plain_text',
text: `🔴 Deal Lost: ${d.dealName}`,
emoji: true,
},
},
{
type: 'section',
fields: [
{ type: 'mrkdwn', text: `*Account:*\n${d.accountName}` },
{ type: 'mrkdwn', text: `*Amount:*\n${d.amount}` },
{ type: 'mrkdwn', text: `*Loss Reason:*\n${d.lossReason}` },
{ type: 'mrkdwn', text: `*Competitor:*\n${d.competitor}` },
{ type: 'mrkdwn', text: `*Owner:*\n${d.ownerName}` },
{ type: 'mrkdwn', text: `*Expected Close:*\n${d.closingDate}` },
],
},
{
type: 'divider',
},
{
type: 'context',
elements: [
{
type: 'mrkdwn',
text: `Deal ID: ${d.dealId} • Logged via Pipedream`,
},
],
},
];
return { blocks };
},
});channel: {{channel}}
ts: {{ts}}
Workflow Canvas > + Add Step > Slack > Send a Message
Add the Slack Step to Post the Message
Click '+ Add Step' and search for 'Slack'. Select the 'Send a Message' action. Connect your Slack workspace by clicking 'Connect Account' — this uses Slack's OAuth flow and requires the channels:write and chat:write scopes. Set the Channel field to your management channel name, like #lost-deal-alerts. In the Blocks field, reference the blocks array exported from the previous code step using the expression picker.
- 1Click '+ Add Step' below the formatting code step
- 2Search for 'Slack' and select it
- 3Choose 'Send a Message' as the action
- 4Click 'Connect Account' and authorize Pipedream in the Slack OAuth popup
- 5Set Channel to '#lost-deal-alerts' (or your channel name)
- 6In the Blocks field, click the expression picker and reference steps.format_message.blocks
Workflow Canvas > Format Code Step > Edit Code
Add Error Handling for Missing Fields
Not every lost deal in Zoho will have a Competitor or Loss Reason filled in. If your Slack message template references these fields and they're null, the message either breaks or posts blank lines. Add a short code step before the Slack step (or inside the formatter) to set default values: 'Not specified' for Loss Reason and 'Unknown' for Competitor. This keeps the Slack message clean and readable even for incomplete records.
- 1Open the formatting code step from Step 7
- 2Add null-coalescing defaults for Loss_Reason and Competitor fields
- 3Set fallback text: Loss_Reason ?? 'Not specified', Competitor ?? 'Unknown'
- 4Click Test to confirm the message renders correctly when fields are empty
Workflow Canvas > Deploy Button (top-right)
Deploy and Enable the Workflow
Click the blue 'Deploy' button in the top-right corner of the Pipedream workflow canvas. The workflow status changes from 'Development' to 'Active'. From this point, every time a deal is edited in Zoho CRM and saved as Lost, the webhook fires, Pipedream processes it, and the Slack alert posts — automatically, with no manual trigger required. Check the 'Event History' tab over the next 24 hours to confirm real events are flowing through correctly.
- 1Click the blue 'Deploy' button in the top-right corner
- 2Confirm the status badge changes to 'Active'
- 3Mark a real deal as Lost in Zoho CRM to test end-to-end
- 4Check the Slack channel for the alert within 30 seconds
- 5Review Event History in Pipedream to confirm the run completed without errors
Workflow Canvas > Settings (gear icon) > Error Handling
Set Up Error Notifications
In Pipedream, click on the workflow settings (gear icon near the workflow name). Under 'Error Handling', enter an email address or Slack channel to receive alerts when the workflow fails. This matters because Zoho webhook failures are silent — if Pipedream has an error, no Slack message posts and no one knows. Routing errors to a separate #pipedream-errors channel gives you immediate visibility without cluttering the management channel.
- 1Click the gear icon near the workflow title
- 2Go to the 'Error Handling' section
- 3Enter your email or a Slack webhook URL for error alerts
- 4Click Save
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
Use Pipedream for this if your team has someone who can read JavaScript and wants sub-30-second alert delivery with zero polling overhead. The instant webhook processing is the main reason to choose Pipedream here — Zoho fires the webhook, Pipedream receives it in milliseconds, and the Slack message posts before a rep has even closed the deal record tab. The Node.js code steps also let you do real data shaping: null checks, deduplication with the built-in data store, and Block Kit formatting that makes the alert actually readable. The one scenario where you'd skip Pipedream: if your team has zero coding tolerance. The Zoho-specific steps in Pipedream's UI are fewer and less polished than Zapier's, and the filter logic requires code. For a fully no-code setup, Zapier handles this workflow adequately.
Pipedream's pricing is credit-based. This workflow costs roughly 3 credits per run — one for the trigger, one for each code step, one for the Slack step. At 50 lost deals per month (reasonable for a 20-person sales team), that's 150 credits/month. Pipedream's free tier includes 10,000 credits/month, so this workflow runs free until you hit roughly 3,300 lost deals per month. The paid Basic plan at $19/month adds 100k credits. Compare that to Zapier, where 50 Zap runs/month on the free tier is fine, but crossing 750 runs costs $19.99/month — and Zapier counts each two-step Zap as one task, so the math is similar at low volume. Pipedream is meaningfully cheaper if you're already using it for other workflows and sharing the credit pool.
Zapier's Zoho CRM trigger is more polished — it has a built-in 'Deal Stage Changed' trigger that fires only on stage transitions, which means you don't need a filter code step. That's a real advantage for non-coders. Make has better visual error tracing — you can see exactly which module failed and why, which helps when Zoho's webhook payload is malformed. n8n gives you self-hosted deployment, which matters if your org has data residency requirements and can't send deal data through a US-based SaaS. Power Automate has native Dynamics 365 integration but Zoho support is weak — you'd use a generic HTTP trigger, which means more setup than Pipedream's OAuth-based Zoho connection. Pipedream wins on speed, code flexibility, and the data store deduplication feature — none of the competitors offer built-in key-value storage that's this easy to use inside a workflow step.
Three things you'll hit after setup. First: Zoho's webhook payload structure changes depending on how the webhook is configured. If you add or remove fields in the Zoho webhook Parameters section after your Pipedream workflow is live, the field paths in your code steps break silently — no error, just blank fields in Slack. Version your webhook configuration. Second: the Competitor field in Zoho CRM is a text field by default, not a picklist — which means you'll get 'Salesforce', 'salesforce', 'SFDC', and 'SF' as four different competitors in your Slack alerts. Standardize it as a picklist in Zoho before building the automation, or add normalization logic in the code step. Third: Pipedream's free tier throttles concurrent executions. If your team closes a batch of deals at quarter-end and 10 webhook events fire in 5 seconds, some will queue. At high concurrency, upgrade to a paid plan to guarantee parallel execution.
Ideas for what to build next
- →Log Loss Reasons to a Zoho CRM Report or Google Sheet — Add a second branch in the Pipedream workflow that writes each lost deal's reason code and competitor to a Google Sheet or Zoho Analytics dataset, building a running tally that management can review weekly without scrolling through Slack history.
- →Route Alerts by Competitor to Different Slack Channels — Extend the formatter code step to check the Competitor field and post to different channels — #competitive-intel for known competitors and #lost-deal-alerts for everything else — so your product team sees competitive losses without noise from budget or timing losses.
- →Create a Follow-Up Task in Zoho CRM on Every Loss — Add a Zoho CRM step after the Slack post that automatically creates a follow-up activity on the lost deal record — assigned to the deal owner — with a 30-day re-engagement task, so no lost deal goes completely cold without a scheduled touchpoint.
Related guides
How to Share Notion Meeting Notes to Slack with Pipedream
~15 min setup
How to Share Notion Meeting Notes to Slack with Power Automate
~15 min setup
How to Share Notion Meeting Notes to Slack with n8n
~20 min setup
How to Send Notion Meeting Notes to Slack with Zapier
~8 min setup
How to Share Notion Meeting Notes to Slack with Make
~12 min setup
How to Create Notion Tasks from Slack with Pipedream
~15 min setup