Intermediate~20 min setupCommunication & CRMVerified April 2026
Slack logo
Close logo

How to Send Close Deal Alerts to Slack with n8n

Fires a Slack message to your sales channel the moment a deal in Close hits a target stage or value threshold — no polling, no delay.

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

Best for

Inside sales teams who need instant visibility on deal stage changes without tab-switching into Close all day.

Not ideal for

Teams that only want a daily digest — use a scheduled workflow with a Slack Block Kit summary instead.

Sync type

real-time

Use case type

notification

Real-World Example

💡

A 12-person SaaS sales team uses this to post to #wins-and-pipeline the moment any deal moves to 'Contract Sent' or exceeds $25,000 in value. Before this workflow, reps refreshed Close manually and missed stage changes for 2–4 hours on average. Now the team sees a Slack alert within 15 seconds of the update firing in Close.

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.

Close admin access to create webhooks under Settings > Integrations
Slack app with 'chat:write' and 'channels:read' OAuth scopes installed in your workspace
n8n instance running (cloud or self-hosted) with external webhook access — self-hosted requires a publicly reachable URL or ngrok tunnel during testing
Target Slack channel already created and the Slack bot invited to it with /invite before running the workflow

Optional

Close API key available at Settings > API Keys (needed if you add a lookup step to resolve owner IDs to names)

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Deal / Opportunity IDdata.id
Deal Namedata.note
Pipeline Stagedata.status_label
Deal Value (cents)data.value
Lead / Company Namedata.lead_name
Date Updateddata.date_updated
Event Typeevent
2 optional fields▸ show
Assigned Owner IDdata.assigned_to
Value Currencydata.value_currency

Step-by-Step Setup

1

n8n Dashboard > Workflows > + New Workflow

Create a new n8n workflow

Log into your n8n instance and click the orange '+ New Workflow' button in the top-right corner of the Workflows dashboard. Give it a clear name like 'Close → Slack Deal Alerts' so it's findable later. You'll land on a blank canvas with an empty trigger node waiting to be configured. This is where you'll drop the webhook trigger in the next step.

  1. 1Click '+ New Workflow' in the top-right corner
  2. 2Click the workflow title field at the top and type 'Close → Slack Deal Alerts'
  3. 3Click the empty trigger node in the center of the canvas to open the node picker
What you should see: You should see an empty workflow canvas with a single placeholder node labeled 'Add first step'.
2

Canvas > Add Node > Webhook

Add a Webhook trigger node

In the node picker, search for 'Webhook' and select it. Set the HTTP Method to POST. n8n will generate a unique webhook URL — copy this URL immediately, you'll paste it into Close in the next step. Set Authentication to 'None' for now (Close sends a shared secret you can validate in a later step). Switch the workflow to 'Test' mode and click 'Listen for Test Event' so n8n is ready to receive a payload from Close.

  1. 1Click the trigger placeholder node and search 'Webhook'
  2. 2Select 'Webhook' from the trigger list
  3. 3Set HTTP Method to 'POST'
  4. 4Copy the test webhook URL shown in the node panel
  5. 5Click 'Listen for Test Event' to activate the listener
What you should see: The Webhook node shows a blue 'Waiting for test event...' status banner at the top of the canvas.
Common mistake — n8n gives you two URLs: a test URL and a production URL. They are different. Configure Close with the test URL now, then swap to the production URL before going live. Forgetting this swap is the most common reason alerts stop working after deployment.
n8n
+
click +
search apps
Slack
SL
Slack
Add a Webhook trigger node
Slack
SL
module added
3

Close > Settings > Integrations > Webhooks > Add Webhook

Configure the Close webhook

Open Close in a separate tab and navigate to Settings > Integrations > Webhooks. Click 'Add Webhook'. Paste the n8n test webhook URL into the Endpoint URL field. Under Events, check 'opportunity.updated' — this fires any time a deal's stage, status, or value changes. You can also check 'opportunity.created' if you want alerts on brand-new deals. Save the webhook. Close will immediately send a verification ping to n8n.

  1. 1In Close, click your avatar in the bottom-left and select 'Settings'
  2. 2Navigate to 'Integrations' then 'Webhooks'
  3. 3Click 'Add Webhook'
  4. 4Paste the n8n test webhook URL into 'Endpoint URL'
  5. 5Check 'opportunity.updated' and optionally 'opportunity.created'
  6. 6Click 'Save'
What you should see: Close shows a green checkmark next to the webhook. Back in n8n, the Webhook node displays the raw JSON payload from Close's verification ping.
Common mistake — Close sends the webhook payload with a 'X-Close-Signature' header for security validation. You don't need to validate it to get started, but skip it and anyone with your webhook URL can POST fake deal alerts into Slack.
4

n8n Canvas > Webhook Node > Output Panel

Inspect the incoming payload

Trigger a real stage change in Close by opening any test deal and moving it to a different pipeline stage. Return to n8n — the Webhook node should now show the full JSON payload in the output panel on the right. Expand the 'data' object to find the fields you'll use: 'status_label', 'value', 'lead_name', 'assigned_to', and 'date_updated'. Pin this test data by clicking the pin icon so you can build the rest of the workflow without needing to fire Close again.

  1. 1In Close, open a test deal and change its pipeline stage
  2. 2Return to n8n and click the Webhook node to see the output
  3. 3Expand the 'data' object in the output panel
  4. 4Click the pin icon (📌) to pin the test data
What you should see: The Webhook node output panel shows a structured JSON object with fields like 'status_label', 'value_formatted', 'lead_name', and 'assigned_to_name' visible.
Common mistake — The 'value' field in Close's webhook payload is in cents (integer), not dollars. A $5,000 deal arrives as 500000. You must divide by 100 in your code node or the Slack message will show wildly wrong numbers.
5

Canvas > + Add Node > Flow > IF

Add an IF node to filter relevant stage changes

Not every deal update deserves a Slack ping. Add an 'IF' node after the Webhook. Set Condition 1 to check if 'data.status_label' equals any of your target stages — for example, 'Contract Sent', 'Won', or 'Needs Attention'. Add a second condition with OR logic to catch high-value deals: check if 'data.value' (the raw integer) is greater than or equal to your threshold (e.g., 2500000 for $25,000). Route only matching deals to the next step.

  1. 1Click the '+' connector below the Webhook node
  2. 2Search 'IF' and select the IF node
  3. 3Set Condition 1: field '{{$json.data.status_label}}', operation 'Equal', value 'Contract Sent'
  4. 4Click '+ Add Condition' and set OR logic for your value threshold
  5. 5Set Condition 2: field '{{$json.data.value}}', operation 'Larger or Equal', value '2500000'
What you should see: The IF node shows two output branches: 'true' (deals matching your filters) and 'false' (everything else). Test data routed to 'true' with your pinned payload.
Common mistake — If you target multiple stages, you need multiple IF conditions chained with OR. Using AND by accident means a deal must match ALL conditions simultaneously — it will silently drop most alerts.
Slack
SL
trigger
filter
Condition
matches criteria?
yes — passes through
no — skipped
Close
CL
notified
6

Canvas > + Add Node > Core > Code

Add a Code node to format the Slack message

Add a 'Code' node after the IF node's 'true' branch. This is where you'll convert the raw Close payload into a clean, readable Slack message. Write JavaScript to pull the deal name, stage, value (divided by 100), owner, and a direct link to the deal in Close. Format the value as a dollar amount using toLocaleString(). You'll build the Slack Block Kit JSON here so the alert looks polished — bold deal name, stage badge, value, and a clickable 'View in Close' button.

  1. 1Click the '+' connector on the IF node's 'true' output
  2. 2Search 'Code' and select the Code node
  3. 3Set Language to 'JavaScript'
  4. 4Paste your formatting code into the editor (see Pro Tip below)
  5. 5Click 'Test Step' to confirm output renders correctly
What you should see: The Code node output panel shows a JSON object with 'blocks' array containing formatted Slack Block Kit sections ready to send.
Common mistake — Map fields using the variable picker — don't type field names manually. Hand-typed variable names often have invisible spacing errors that produce blank output.

Paste this into the Code node (step 6) between the IF node and the Slack node. It converts the raw Close payload into a fully formatted Slack Block Kit message, handles the cents-to-dollars conversion, picks the right emoji based on stage, and builds the direct Close deal URL.

JavaScript — Code Node// n8n Code node — Close to Slack Block Kit formatter
▸ Show code
// n8n Code node — Close to Slack Block Kit formatter
// Runs once per deal event that passed the IF filter
const item = $input.first().json;

... expand to see full code

// n8n Code node — Close to Slack Block Kit formatter
// Runs once per deal event that passed the IF filter

const item = $input.first().json;
const data = item.data;
const eventType = item.event;

// Convert cents to formatted dollar string
const valueInDollars = (data.value / 100).toLocaleString('en-US', {
  style: 'currency',
  currency: data.value_currency || 'USD'
});

// Pick emoji based on stage label
const stageEmojis = {
  'Won': '🏆',
  'Contract Sent': '📋',
  'Negotiation': '🤝',
  'Demo Scheduled': '📅',
  'Needs Attention': '⚠️'
};
const emoji = stageEmojis[data.status_label] || '📌';

// Format the timestamp
const updatedAt = new Date(data.date_updated);
const formattedDate = updatedAt.toLocaleString('en-US', {
  month: 'short',
  day: 'numeric',
  year: 'numeric',
  hour: 'numeric',
  minute: '2-digit'
});

// Build the Close deal URL
const dealUrl = `https://app.close.com/opportunity/${data.id}/`;

// Determine header text
const isNew = eventType === 'opportunity.created';
const headerText = isNew
  ? `${emoji} New Deal — ${data.status_label}`
  : `${emoji} Deal Updated — ${data.status_label}`;

// Build Slack Block Kit payload
const blocks = [
  {
    type: 'header',
    text: {
      type: 'plain_text',
      text: headerText,
      emoji: true
    }
  },
  {
    type: 'section',
    fields: [
      {
        type: 'mrkdwn',
        text: `*Company:*\n${data.lead_name || 'Unknown'}`
      },
      {
        type: 'mrkdwn',
        text: `*Value:*\n${valueInDollars}`
      },
      {
        type: 'mrkdwn',
        text: `*Stage:*\n${data.status_label}`
      },
      {
        type: 'mrkdwn',
        text: `*Updated:*\n${formattedDate}`
      }
    ]
  },
  {
    type: 'actions',
    elements: [
      {
        type: 'button',
        text: {
          type: 'plain_text',
          text: 'View in Close',
          emoji: true
        },
        url: dealUrl,
        style: 'primary'
      }
    ]
  },
  {
    type: 'divider'
  }
];

return [{ json: { blocks, text: `${emoji} ${data.lead_name} — ${data.status_label} (${valueInDollars})` } }];
message template
🔔 New Record: {{text}} {{user}}
channel: {{channel}}
ts: {{ts}}
#sales
🔔 New Record: Jane Smith
Company: Acme Corp
7

Canvas > + Add Node > Action in App > Slack > Message > Send

Add a Slack node and configure the message

Add a 'Slack' node after the Code node. In the Credentials field, click 'Create New Credential' and authenticate with your Slack workspace using OAuth2 — this requires the 'chat:write' and 'channels:read' scopes. Set Resource to 'Message' and Operation to 'Send'. In the Channel field, type the exact channel name (e.g., #deals-pipeline). Set the 'Blocks' field to an expression pointing to your Code node output: '{{$json.blocks}}'.

  1. 1Click '+' after the Code node and search 'Slack'
  2. 2Select 'Slack' then choose 'Message' resource and 'Send' operation
  3. 3Click 'Create New Credential' and complete Slack OAuth flow
  4. 4Set Channel to your target channel name (e.g., '#deals-pipeline')
  5. 5Set Blocks field to expression: {{$json.blocks}}
  6. 6Set Text field to a fallback string like 'New deal alert from Close'
What you should see: The Slack node shows a green success badge and the Output panel displays the Slack API response with 'ok: true'.
Common mistake — The Slack node must be added to the channel before it can post. If the bot isn't in the channel yet, type /invite @YourBotName in Slack first — otherwise you'll get a 'channel_not_found' or 'not_in_channel' error with no helpful detail in n8n.
8

Canvas > Slack Node > Settings > Continue on Fail

Add error handling with a fallback branch

Select the Slack node and open its Settings tab. Enable 'Continue on Fail' so a Slack API hiccup doesn't silently kill the workflow. Then add a second branch from the Slack node: connect an 'IF' node checking if the Slack response field 'ok' equals false. Route failures to a 'Send Email' or secondary Slack channel node as a fallback alert so you know when the main notification fails.

  1. 1Click the Slack node to open its panel
  2. 2Click the 'Settings' tab inside the node panel
  3. 3Toggle 'Continue on Fail' to ON
  4. 4Click '+' on the Slack node's output and add an IF node
  5. 5Set condition: '{{$json.ok}}' equals false
  6. 6Add a fallback notification node on the 'true' branch
What you should see: The canvas shows two outputs from the Slack node — the main success path and a fallback error path. Both connect to terminal nodes.
Common mistake — Setting 'Continue on Fail' without the fallback branch means errors are swallowed silently. You'll think alerts are working when they aren't. Always pair the toggle with an actual error notification.
9

n8n Canvas > Test Workflow button

Test end-to-end with a live deal change

With the workflow still in Test mode, go to Close and move a real deal into one of your target stages (or update its value above your threshold). Return to n8n and walk through each node's output to confirm the data flows correctly: Webhook receives payload → IF node routes to 'true' → Code node formats the message → Slack node returns 'ok: true'. Check your Slack channel to confirm the message appeared. Verify the dollar value, deal name, and stage label are all correct.

  1. 1Click 'Test Workflow' in the top-right of n8n canvas
  2. 2In Close, open a deal and change its stage to one of your target stages
  3. 3Return to n8n and click each node to inspect its output
  4. 4Open Slack and confirm the alert message appeared in the correct channel
What you should see: The Slack channel shows a formatted Block Kit message with the correct deal name, stage, value in dollars, owner name, and a working 'View in Close' link.
n8n
▶ Run once
executed
Slack
Close
Close
🔔 notification
received
10

Close > Settings > Integrations > Webhooks | n8n Canvas > Activate toggle

Swap webhook URL and activate for production

Click the Webhook node and copy the Production URL (different from the test URL). Go back to Close Settings > Integrations > Webhooks, click your webhook, and replace the test URL with the production URL. Save. Back in n8n, click the 'Activate' toggle in the top-right corner of the canvas — it turns green. The workflow is now live and will fire on real deal changes without manual intervention.

  1. 1In n8n, click the Webhook node and copy the 'Production URL'
  2. 2In Close, navigate to Settings > Integrations > Webhooks
  3. 3Click your existing webhook and replace the URL with the production URL
  4. 4Click 'Save' in Close
  5. 5In n8n, click the gray 'Inactive' toggle in the top-right — it turns green
What you should see: The n8n workflow shows a green 'Active' badge. The Close webhook settings show your production URL. Fire one more test stage change and confirm the Slack alert appears within 15 seconds.
Common mistake — Copy the webhook URL carefully — it expires if you regenerate it, and any scenarios using the old URL will silently stop working.

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 want full control over the message format and filtering logic without paying per-task fees. The Block Kit formatting in the Code node takes 20 minutes to set up once and then it's yours — no template limits, no per-message charges. A second reason: the IF node logic can get complex (multiple stages, value thresholds, assigned rep filters) and n8n handles branching cleanly without hitting plan restrictions. The one scenario where you'd skip n8n: if your team has zero JavaScript familiarity and you need this running today, Zapier's Slack integration gets the basics done in 8 minutes with no code.

Cost

Cost math is straightforward. Each deal stage change = 1 webhook execution = roughly 4-5 n8n tasks (Webhook → IF → Code → Slack → error check). A sales team that moves 200 deals per month hits around 1,000 tasks/month. n8n Cloud's Starter plan includes 2,500 tasks/month at $20/month. Self-hosted n8n is $0 in execution cost (just server fees). Zapier at the same volume costs $49/month on the Professional plan. Make handles 1,000 operations/month on the free tier, which covers this workflow entirely if your deal velocity is under 200/month.

Tradeoffs

Make's scenario builder has a built-in Close module with pre-mapped fields — no Code node required, and the Block Kit JSON can be pasted directly into a text field. That's faster for first-time setup. Zapier's 'Trigger on New Event' for Close is dead simple but the Slack message customization tops out at a flat text string — no Block Kit buttons without a Code by Zapier step. Power Automate has no native Close connector, so you'd route through a generic HTTP action anyway, which removes any PA advantage. Pipedream's Close + Slack pre-built actions are clean and the code step runs Node.js natively, making it a genuine alternative to n8n for this workflow — the main difference is n8n's self-hosted option keeps your deal data off third-party servers, which matters for some sales teams.

Three things you'll run into after setup. First, Close fires 'opportunity.updated' for every field edit — a rep adding a note fires the same event as a stage change. Without a tight IF condition on 'status_label', you'll send dozens of irrelevant Slack pings per day and the team will start ignoring all of them. Second, the 'assigned_to' field in the webhook payload is a user ID string, not a name. If you display the raw ID in Slack ('Assigned to: user_def456'), it's useless — build the lookup step early. Third, if you're self-hosting n8n behind a reverse proxy, make sure the proxy isn't stripping the 'X-Close-Signature' header. You don't need it to start, but if you add signature validation later and the header is missing, every webhook will fail validation silently.

Ideas for what to build next

  • Add a daily pipeline digestBuild a second n8n workflow on a scheduled trigger (9 AM daily) that pulls all open deals from the Close API and posts a structured summary to #sales-standup — counts by stage, total pipeline value, and deals that haven't moved in 7+ days.
  • Route alerts to deal owner's DMInstead of (or in addition to) posting to a shared channel, use the resolved Slack user ID to send a direct message to the assigned rep when their specific deal changes stage. Requires mapping Close user IDs to Slack user IDs in a lookup table.
  • Trigger a task in Close when a deal stallsExtend this workflow with a reverse action: if a deal hasn't moved stages in 5+ days, automatically create a follow-up task in Close via the API and notify the rep in Slack with a link to the task. Turns passive alerts into active nudges.

Related guides

Was this guide helpful?
Slack + Close overviewn8n profile →