How to validate a Monday.com Webhook in PHP

Is there any one here that can display a PHP script example to validate a monday.com webhook and make it work.

I am stuck at sending the response back to the http post request to validate the webhook url.

Hey Frank!

Dipro here ā€“ what have you got so far? I donā€™t have a PHP example for this, but would a Node.js example help you understand the logic?

Cheers,
Dipro

@dipro That would certainly help meā€¦

Yes I would like to see the Node.js example

Seriouslyā€¦ The documentation of this feature is horrible. The guide even has major grammatical mistakes which is just lazy. I guess this feature is not that important to the dev team? Itā€™s up to us to figure out how to integrate? rude!

Too bad because Monday.com Webhooks would basically eliminate the barriers many developers face in beating their workflows into the Monday.com box.

I have no idea about Node.js but below is how far Iā€™ve gotten with PHPā€¦ still working on how to actually validate the ā€œchallengeā€ JSON.

context:

  • I have a file called webhooks_processor.php on our company website.
  • that file logs POST requests to an error file called ā€œwebhook.logā€ that is also on our server so I can see what the heck monday.com webhooks are sending.
  • not to overstate the obvious (because it was not to me at first) but at the Board > Integrations > webhooks > ā€œWhen a column changes, send a webhookā€ > WebhookURL Prompt, I am entering the url of my webhooks_processor.php file.

code:

So far, all I can get is boolean return of ā€œTRUEā€ out of this. However, I have no idea if I am a accurately directing the validation response because its not mentioned in the webhook documentation! Now Iā€™m sending it to: https://api.monday.com/v2/ but I donā€™t know. This is not really an API feature.

<?php

// set a timestamp for tracking events in the log file
$now = date("Y.m.d @ G:i");

//capture the monday.com webhook challenge as a php object
$challenge_received = json_decode($GLOBALS['HTTP_RAW_POST_DATA'])->challenge;

// write the challenge to a log file for debugging
error_log("$now: JSON challenge: $challenge_received\n", 3, "webhook.log");

// prepare JSON response
$challenge_response = json_encode($challenge_received);

// initiate cURL
$ch = curl_init("https://api.monday.com/v2/");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $challenge_response);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));

// execute the request
$result = curl_exec($ch);

// execute the request
$result = curl_exec($ch);

// inspect result
if ($result === FALSE) {
    error_log("$now: the result object returned FALSE\n", 3, "webhook.log");
} else {
    error_log("$now: response to challenge validation attempt: $result\n", 3, "webhook.log");
}
?>

I hope this helps and we can move this forward somehow.

@robzinn, hereā€™s my PHP code to authorize it.

if ($request->has('challenge')) {
     return response()->json(['challenge' => $request->input('challenge')]);
} 

This example is part of a Laravel app but you should be returning the json_encoded challenge as a reply to the POST.

Thanks @darren. I have no idea what Laravel is but could you share or direct me to more of the code from your example? I can capture the challenge and send it back but to where!? sending it to

$ch = curl_init("https://api.monday.com/v2/");

was just a hunch based on the API documentation and must be wrong.

Iā€™ve tried sending it to

$_SERVER['REMOTE_ADDR']

Which is the only header I could find coming in from the webhook that might be a remote address, but it was an IP address, not a URL.

Perhaps I am missing somethingā€¦ can you just call ā€œrespondā€ to a POST somehow in PHP and send back a response without knowing the actual address?

Update: Now seeing this error in the JS console:

Access to XMLHttpRequest at ā€˜https://api-gw.monday.com/automations/automationsā€™ from origin ā€˜https://mymnodayspace.monday.comā€™ has been blocked by CORS policy: No ā€˜Access-Control-Allow-Originā€™ header is present on the requested resource.

I think this means monday.com servers are not setup for CORS correctly as both requests are on the same domain.

I finally figured it out. The documentation could have been better explained
because itā€™s quite simple if you explained it better. Below is the simple code I figured out

after trying to send back to a url. It is a simple echo to send back the challenge.

<?php //grab the challenge sent by Monday.com $challenge = file_get_contents('php://input'); //echo back the challenge echo $challenge; ?>
1 Like

OMG seriously! Thank you so much @renow! If only I had the last 3 days back! :wink:

Great, I will keep working and post any additional insights.

@renow thank you for posting this! Is there anything else that needs to be included? I tried:

<?php
$challenge = file_get_contents('php://input'); 
echo $challenge; 
?>

but I get a failed to communicate with URL error. Does it need to be encoded?

@mru if Monday sends 1234 as the challenge then you need to return this:

{ā€œchallengeā€:ā€œ1234ā€}

@darren thank you for the response. I understand that I need to return the challenge but for some reason it keeps getting denied when I try to link the integration. I have it formatted exactly how you have it and Iā€™ve verified that I am getting a challenge.

@mru are you using a secure url? It has to be a ā€œhttps://example.comā€ url.

If @mru is seeing the webhook hitting his system then Iā€™d guess he must be using a secure url. @mru are you returning it with Content-Type set to application/json? I donā€™t know if itā€™s mandatory but thatā€™s how Iā€™m returning it.

@renow yes the server is https. @darren Iā€™ve tried with and without. It should be this shouldnā€™t it? Sorry PHP isnā€™t my strong suit.
header('content-type: application/json');
Iā€™ve been logging the request to verify the format and it is: {ā€œchallengeā€:ā€œ1234ā€}. I know with GraphQL we have to escape special characters but Iā€™m assuming it isnā€™t the case here.

Does anyone have suggestion for node.js Iā€™ve tried everything: exports.handler = event => {
console.log( {ā€œchallengeā€: JSON.parse(event.body).challenge});
const response = {
statusCode: 200,
body: JSON.parse(event.body)

};
console.log(response);
return response;
};

Finally got it to work. Below is my index.js file using node.js

exports.handler = async event => {
  console.log( {"challenge": JSON.parse(event.body).challenge});
  const response = {
    statusCode: 200,
    body: event.body
    
  };
  console.log(response);
  return response;
};

Spoke to @mru about this issue ā€“ looks like rebuilding the challenge as a new JSON object was his solution:

<?php

$data = json_decode(file_get_contents('php://input'), true);

$message = [

"challenge" => $data["challenge"]

];

file_put_contents("response1.log", print_r(json_encode($data), true));

header('content-type: application/json');

echo json_encode($message);

?>

Can you explain more,it would be helpful