How to validate a Webhook in PHP

Is there any one here that can display a PHP script example to validate a 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?

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 Webhooks would basically eliminate the barriers many developers face in beating their workflows into the 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.


  • 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 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.


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: but I don’t know. This is not really an API feature.


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

//capture the 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("");
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("");

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

I’ve tried sending it to


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 ‘’ from origin ‘’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

I think this means 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 $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:

$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:


@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 “” 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)

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
  return response;

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


$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);