This workflow corresponds to n8n.io template #17492 — we link there as the canonical source.
This workflow follows the HTTP Request → Stopanderror recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"meta": {
"description": "When a lead is created, verify HMAC, ack, enrich via GET /v1/leads/:id, notify Slack.",
"templateCredsSetupCompleted": false
},
"name": "Zivvy CRM \u2014 New Lead \u2192 Slack",
"tags": [
{
"name": "zivvy"
},
{
"name": "crm"
},
{
"name": "leads"
}
],
"nodes": [
{
"id": "33d37d60-4280-4e36-bd8e-1aa74360dac8",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-368,
16
],
"parameters": {
"width": 480,
"height": 880,
"content": "## Zivvy CRM \u2014 New Lead \u2192 Slack\n\n### How it works\n\nThis workflow receives new-lead webhook events from Zivvy CRM and validates their signature before doing anything else. Authenticated events are checked against the expected event type, while bad signatures are stopped and unrelated events are ignored. Matching lead events are formatted into a Slack message, with a nearby optional Zivvy API enrichment request, and then sent to Slack through a webhook URL.\n\n### Setup steps\n\n- Configure the Zivvy webhook in Zivvy CRM to point to the n8n webhook URL generated by the \"Zivvy Webhook\" node.\n- Set the shared Zivvy signing secret or verification parameters used by the \"Verify Zivvy Signature\" code node.\n- Review the \"Signature OK?\" and \"Event Match?\" conditions so they match Zivvy's payload structure and the specific new-lead event name.\n- Set the SLACK_WEBHOOK_URL environment variable to a valid Slack incoming webhook URL.\n- Configure any required Zivvy API authentication for the \"Enrich from Zivvy API\" request if that enrichment branch is used.\n\n### Customization\n\nAdjust the fields in \"Build Notification\" to change the Slack message text, channel routing metadata, or included lead details. Update the event filter if you want to notify Slack for additional Zivvy CRM event types."
},
"typeVersion": 1
},
{
"id": "4cbbbc1f-4563-4f39-a120-14e61fa10a86",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
192,
224
],
"parameters": {
"color": 7,
"width": 720,
"height": 304,
"content": "## Receive and verify webhook\n\nThis left-side intake cluster receives the Zivvy webhook, runs custom signature verification, and branches based on whether the request is authentic."
},
"typeVersion": 1
},
{
"id": "c14251c5-24f3-4810-8c49-661fa57526ac",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
960,
144
],
"parameters": {
"color": 7,
"width": 432,
"height": 592,
"content": "## Filter invalid events\n\nThis central branching cluster handles requests that should not continue: bad signatures are stopped with an error, and unmatched Zivvy events are skipped. It also contains the event-type decision point that routes valid matching leads onward."
},
"typeVersion": 1
},
{
"id": "17ca279d-6290-465f-b2c6-4b588ef27d8a",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1440,
16
],
"parameters": {
"color": 7,
"width": 432,
"height": 496,
"content": "## Enrich and notify Slack\n\nThis right-side output cluster prepares the Slack notification, optionally calls the Zivvy API for lead enrichment, and posts the formatted message to Slack via an incoming webhook."
},
"typeVersion": 1
},
{
"id": "c9af3951-2923-44da-805e-5f7a37080e8b",
"name": "When New Lead in Zivvy",
"type": "n8n-nodes-base.webhook",
"position": [
240,
360
],
"parameters": {
"path": "zivvy/crm-leads",
"options": {
"rawBody": true,
"ignoreBots": true,
"responseCode": 200
},
"httpMethod": "POST",
"responseData": "firstEntryJson",
"responseMode": "onReceived"
},
"typeVersion": 2
},
{
"id": "eec962ba-4da0-46ae-9d99-32ff1aecde31",
"name": "Validate Zivvy Signature",
"type": "n8n-nodes-base.code",
"position": [
500,
360
],
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "/**\n * Verify Zivvy webhook HMAC.\n * Production (zivvy_brand/api/webhooks.py):\n * signature = HMAC_SHA256(secret, raw_body_bytes).hexdigest()\n * header = \"sha256=\" + signature\n *\n * Set env ZIVVY_WEBHOOK_SECRET (n8n \u2192 Settings \u2192 Variables)\n * or edit SECRET below for local tests only.\n *\n * Docs: https://docs.n8n.io/code/code-node/\n * https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/\n */\nconst crypto = require('crypto');\n\nconst SECRET = (typeof $env !== 'undefined' && $env.ZIVVY_WEBHOOK_SECRET)\n ? $env.ZIVVY_WEBHOOK_SECRET\n : 'CHANGE_ME_ZIVVY_WEBHOOK_SECRET';\n\nif (!SECRET || SECRET.startsWith('CHANGE_ME')) {\n throw new Error('Set n8n variable ZIVVY_WEBHOOK_SECRET to your Zivvy webhook signing secret.');\n}\n\nconst item = $input.first();\nconst headers = item.json.headers || {};\nconst lower = {};\nfor (const [k, v] of Object.entries(headers)) lower[String(k).toLowerCase()] = v;\n\nconst sigHeader = String(lower['x-zivvy-signature'] || '');\nconst eventHeader = String(lower['x-zivvy-event'] || '');\nconst deliveryHeader = String(lower['x-zivvy-delivery'] || '');\n\nlet rawBody = '';\nif (item.binary && item.binary.data) {\n const bin = item.binary.data;\n rawBody = Buffer.from(bin.data, bin.encoding || 'base64').toString('utf8');\n} else if (typeof item.json.body === 'string') {\n rawBody = item.json.body;\n} else if (item.json.body && typeof item.json.body === 'object') {\n // Compact re-serialize \u2014 matches Python json.dumps(..., separators=(',', ':'))\n rawBody = JSON.stringify(item.json.body);\n} else {\n // Some n8n versions flatten the body onto json\n const { headers: _h, params: _p, query: _q, webhookUrl: _w, ...rest } = item.json;\n rawBody = JSON.stringify(rest);\n}\n\nconst expected = 'sha256=' + crypto\n .createHmac('sha256', SECRET)\n .update(rawBody, 'utf8')\n .digest('hex');\n\nconst a = Buffer.from(sigHeader);\nconst b = Buffer.from(expected);\nconst ok = a.length === b.length && crypto.timingSafeEqual(a, b);\n\nlet payload;\ntry {\n payload = JSON.parse(rawBody);\n} catch {\n payload = item.json.body || item.json;\n}\n\nif (!ok) {\n return [{\n json: {\n signature_valid: false,\n error: 'invalid_signature',\n event: eventHeader || payload?.event,\n delivery_id: deliveryHeader\n }\n }];\n}\n\nreturn [{\n json: {\n signature_valid: true,\n event: eventHeader || payload.event,\n delivery_id: deliveryHeader,\n resource: payload.resource,\n timestamp: payload.timestamp,\n data: payload.data || {},\n payload\n }\n}];",
"language": "javaScript"
},
"typeVersion": 2
},
{
"id": "13537756-b5a8-4c3b-9028-9ee0ad927f66",
"name": "If Signature Valid",
"type": "n8n-nodes-base.if",
"position": [
760,
360
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "59c4c462-f9ac-4189-88c8-e9e2e67576ca",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.signature_valid }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "260a097a-37d0-4ba0-afe8-b15854ad0d5e",
"name": "Stop on Invalid Signature",
"type": "n8n-nodes-base.stopAndError",
"position": [
1000,
560
],
"parameters": {
"errorMessage": "Zivvy webhook signature invalid"
},
"typeVersion": 1
},
{
"id": "ca8fa5ac-8ecd-4a34-905d-cb773f80918f",
"name": "Check Event Type",
"type": "n8n-nodes-base.if",
"position": [
1000,
360
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "a4ac3537-d729-4fb9-9afa-3e32ca753b0b",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.event }}",
"rightValue": "leads.created"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "5c2a229b-6115-495a-a067-269f3e3729eb",
"name": "Ignore Unmatched Events",
"type": "n8n-nodes-base.noOp",
"position": [
1240,
560
],
"parameters": {},
"typeVersion": 1
},
{
"id": "9e22f5b6-2284-42ed-a11d-22ad5b9ce127",
"name": "Set Slack Notification Data",
"type": "n8n-nodes-base.set",
"position": [
1480,
360
],
"parameters": {
"mode": "manual",
"options": {},
"assignments": {
"assignments": [
{
"id": "6c7ec1e4-af92-4328-bd32-e60c89d5043c",
"name": "text",
"type": "string",
"value": "={{ '\u2022 *' + $json.event + '*\\n\u2022 Doc: `' + ($json.data.name || '') + '`\\n\u2022 Customer/Supplier: ' + ($json.data.customer || $json.data.supplier || '\u2014') + '\\n\u2022 Employee: ' + ($json.data.employee || '\u2014') + '\\n\u2022 Status: ' + ($json.data.status || '\u2014') + '\\n\u2022 Total: ' + ($json.data.grand_total || '\u2014') + '\\n\u2022 Area: CRM' }}"
},
{
"id": "35bf6a4b-19e2-40ef-aff4-01970da51a95",
"name": "area",
"type": "string",
"value": "CRM"
}
]
},
"duplicateItem": false
},
"typeVersion": 3.4
},
{
"id": "65e94aba-4295-46e3-87fb-99280634bb15",
"name": "Send to Slack Webhook",
"type": "n8n-nodes-base.httpRequest",
"position": [
1720,
360
],
"parameters": {
"url": "={{ $env.SLACK_WEBHOOK_URL }}",
"method": "POST",
"options": {
"timeout": 10000,
"response": {
"response": {
"neverError": true
}
}
},
"jsonBody": "={{ { text: $json.text, blocks: $json.blocks || undefined } }}",
"sendBody": true,
"specifyBody": "json"
},
"typeVersion": 4.2,
"continueOnFail": true
},
{
"id": "9f5fd139-39a7-411f-844f-064f4c1fc3e3",
"name": "Fetch Lead Details from Zivvy",
"type": "n8n-nodes-base.httpRequest",
"position": [
1480,
200
],
"parameters": {
"url": "={{ 'https://api.zivvy.xyz/v1/' + ('leads') + '/' + encodeURIComponent($json.data.name) }}",
"method": "GET",
"options": {
"timeout": 10000,
"response": {
"response": {
"neverError": true
}
}
},
"sendHeaders": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Accept",
"value": "application/json"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"continueOnFail": true
}
],
"active": false,
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": "",
"executionOrder": "v1"
},
"versionId": "39c921f5-267a-410a-ad01-bab95a62f870",
"connections": {
"Check Event Type": {
"main": [
[
{
"node": "Set Slack Notification Data",
"type": "main",
"index": 0
},
{
"node": "Fetch Lead Details from Zivvy",
"type": "main",
"index": 0
}
],
[
{
"node": "Ignore Unmatched Events",
"type": "main",
"index": 0
}
]
]
},
"If Signature Valid": {
"main": [
[
{
"node": "Check Event Type",
"type": "main",
"index": 0
}
],
[
{
"node": "Stop on Invalid Signature",
"type": "main",
"index": 0
}
]
]
},
"When New Lead in Zivvy": {
"main": [
[
{
"node": "Validate Zivvy Signature",
"type": "main",
"index": 0
}
]
]
},
"Validate Zivvy Signature": {
"main": [
[
{
"node": "If Signature Valid",
"type": "main",
"index": 0
}
]
]
},
"Set Slack Notification Data": {
"main": [
[
{
"node": "Send to Slack Webhook",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
httpHeaderAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow receives Zivvy CRM lead creation webhooks, verifies the HMAC signature, fetches lead details from the Zivvy API, and posts a formatted notification to Slack via an incoming webhook. Receives a POST webhook from Zivvy at and captures the raw request body. Verifies…
Source: https://n8n.io/workflows/17492/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow leverages n8n to perform automated Google Maps API queries and manage data efficiently in Google Sheets. It's designed to extract specific location data based on a given list of ZIP code
Automatically qualify, score, and route inbound B2B leads using GPT-4o-mini — no manual review needed.
This workflow receives Bitrix24 deal updates via a webhook, fetches the deal and contact details, and uploads an offline Purchase conversion to the Google Ads Click Conversion API using the deal’s GCL
This workflow triggers on Bitrix24 deal updates, checks whether a deal is qualified and has a GCLID, then uploads an offline click conversion to the Google Ads API with hashed first-party customer ide
This workflow runs a FindMyClient search for a keyword, polls for completion, and extracts any returned email addresses. If emails are found, it splits them into individual items for optional saving t