Recently for a client, I was working to switch over from Make.com to their own n8n install in order to manage some automations. I was struggling to deal with Monday.com’s challenge response to the webhook using n8n. After some finagling with Claude and trial/error with curl
, I was able to build a workflow that got me through.
Here is the n8n workflow json that you can copy and paste:
{
"name": "Monday.com Webhook - Exact Documentation",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "monday-webhook",
"responseMode": "responseNode",
"options": {}
},
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [0, 0],
"webhookId": "2e18be0d-ef25-4009-8724-8906e1700cb0",
"id": "4f6c0d7e-cf39-4b04-af53-303ed741d388"
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.body.challenge }}",
"operation": "isNotEmpty"
}
]
}
},
"name": "If Challenge Exists",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [200, 0],
"id": "d39443cf-ebc2-4426-a612-852a482eb18b"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $node[\"Webhook\"].json[\"body\"] }}",
"options": {
"responseCode": 200
}
},
"name": "Return Challenge JSON",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [400, -100],
"id": "7faa215a-d4d2-466a-98f1-2f83331177e8"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{\"success\": true}",
"options": {
"responseCode": 200
}
},
"name": "Return Success",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [400, 100],
"id": "8faa215a-d4d2-466a-98f1-2f83331177e9"
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "If Challenge Exists",
"type": "main",
"index": 0
}
]
]
},
"If Challenge Exists": {
"main": [
[
{
"node": "Return Challenge JSON",
"type": "main",
"index": 0
}
],
[
{
"node": "Return Success",
"type": "main",
"index": 0
}
]
]
}
},
"meta": {
"instanceId": "f4e93957bea2bfbb949bc11ce90a97c3c32f37ea7ba5e965c8ac9cd10fea6dc3"
}
}
From Claude, here is a full breakdown of the nodes:
Workflow Overview
This workflow handles Monday.com webhook verification and events with 4 nodes connected in a branching pattern.
Node 1: Webhook (Entry Point)
"name": "Webhook"
"type": "n8n-nodes-base.webhook"
- Purpose: Receives incoming HTTP POST requests from Monday.com
- Path:
/webhook/monday-webhook
– This creates the endpoint URL - Response Mode:
responseNode
– Means it waits for another node to send the response (not immediate) - Position:
[0, 0]
– Located at the start of the workflow visually - Webhook ID: A unique identifier for this webhook instance
Node 2: If Challenge Exists (Decision Node)
"name": "If Challenge Exists"
"type": "n8n-nodes-base.if"
- Purpose: Checks if the incoming request contains a
challenge
field - Condition:
{{ $json.body.challenge }}
with operationisNotEmpty
- This checks if there’s a challenge field in the request body
$json.body
refers to the parsed JSON body from the webhook
- Branching: Creates two paths:
- True branch (index 0): Goes to “Return Challenge JSON”
- False branch (index 1): Goes to “Return Success”
Node 3: Return Challenge JSON (True Branch)
"name": "Return Challenge JSON"
"type": "n8n-nodes-base.respondToWebhook"
- Purpose: Responds to Monday.com’s verification challenge
- Response Type:
json
- Response Body:
={{ $node["Webhook"].json["body"] }}
- This returns the ENTIRE body that was received
- Matches Monday’s requirement: return exactly what they sent
- Status Code: 200
- Position:
[400, -100]
– Positioned above (negative Y) the other response node
Node 4: Return Success (False Branch)
"name": "Return Success"
"type": "n8n-nodes-base.respondToWebhook"
- Purpose: Responds to regular webhook events (not challenges)
- Response Type:
json
- Response Body:
{"success": true}
– A simple success acknowledgment - Status Code: 200
- Position:
[400, 100]
– Positioned below (positive Y) the challenge response
Connections (Workflow Logic)
"connections": {
"Webhook": → "If Challenge Exists"
"If Challenge Exists":
- [True] → "Return Challenge JSON"
- [False] → "Return Success"
}
Flow Scenarios
Scenario 1: Monday.com sends verification challenge
- Monday sends: {“challenge”: “abc123xyz”}
- Webhook receives it
- IF node checks: Is challenge present? YES
- Return Challenge JSON sends back: {“challenge”: “abc123xyz”}
- Monday.com verifies and activates webhook
Scenario 2: Monday.com sends actual webhook event
- Monday sends: {“event”: {“type”: “item_created”, …}}
- Webhook receives it
- IF node checks: Is challenge present? NO
- Return Success sends back: {“success”: true}
- Monday.com knows event was received
Key Design Elements
- Response Mode: Uses
responseNode
pattern where the webhook waits for explicit response nodes - Expression Syntax: Uses n8n’s
={{}}
expression format for dynamic values - Node References:
$node["Webhook"].json["body"]
allows accessing data from previous nodes - Conditional Branching: The IF node splits the flow based on whether it’s a verification or regular event
This workflow elegantly handles both Monday.com’s webhook verification process and ongoing event processing in a single, simple flow.
Testing the Monday.com Webhook with cURL
Based on the workflow structure, here are the test commands:
Test 1: Challenge Verification (What Monday.com sends during setup)
bash
curl -X POST https://your-n8n-instance-url.com/webhook/monday-webhook \
-H "Content-Type: application/json" \
-d '{"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"}' \
-v
Expected Response:
json
{"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"}
- Status: 200 OK
- The workflow should echo back the exact JSON it received