
Webhook failing with "Response contained a body"
Hi,
During setup webhook, I have completed signature validation part. It correctly return 200, 401 for relevant situations. But it fails to "Intent To Receive". It shows in the Xero webhook set up page "Response contained a body".
During setup webhook, I have completed signature validation part. It correctly return 200, 401 for relevant situations. But it fails to "Intent To Receive". It shows in the Xero webhook set up page "Response contained a body".
18
Replies

Hi there,
You'll only see that message if your responses to the "Intent To Receive" webhook requests contained information in the body. You need to remove everything being sent in the body of your responses to pass that part of the validation.
Thanks,
Russell
You'll only see that message if your responses to the "Intent To Receive" webhook requests contained information in the body. You need to remove everything being sent in the body of your responses to pass that part of the validation.
Thanks,
Russell

I am having the same issue. How specifically can I remove everything from the body of the response. As far as I can see there's an empty JSON object and a 200 response code in the header. Example below is in php. I am really having trouble here.
$responsePayLoad = '{}';
header('HTTP/1.1 200');
echo $responsePayLoad;
Thanks!
$responsePayLoad = '{}';
header('HTTP/1.1 200');
echo $responsePayLoad;
Thanks!

I think it's not possible from php get webhook validation, I try every combination for response body and always got "Response contained a body"

It sure is, we just had to move the touch point outside project root (not web root). This is partly because Xero coders (or more than likely their business analysts) have no idea what they are doing.
If you'd like an example of this, see their php API (which used to force us to create our own XML) and compare it with this.
If you'd like an example of this, see their php API (which used to force us to create our own XML) and compare it with this.

I'm having this problem as well.
My code is shown below. There's nothing being sent after the headers, but I'm getting that error regardless of what I do. Any suggestions would be greatly appreciated.
One thing I found in some of their documentation is a link to Github's site for webhook Testing. Github has a tool for their webhook integrations that will allow you to see the request/response while troubleshooting issues with webhook creation. If we could see the actual response that Xero is getting back on ITR attempts, it might help to solve the problem.
My code is shown below. There's nothing being sent after the headers, but I'm getting that error regardless of what I do. Any suggestions would be greatly appreciated.
One thing I found in some of their documentation is a link to Github's site for webhook Testing. Github has a tool for their webhook integrations that will allow you to see the request/response while troubleshooting issues with webhook creation. If we could see the actual response that Xero is getting back on ITR attempts, it might help to solve the problem.

$secret = 'cWp15d4e78JcqRfrLxsaz7Zvp6xc4JuuUKt01N+Pa5nAYJTVijl9FWVJPKKHpK/pL+eZNPxtAbjkwBSMxNZpQA==';
$headers = getallheaders();
$timestamp = time();
$payload = file_get_contents('php://input');
$signature = '';
$hash = base64_encode(hash_hmac('sha256', $payload, $secret, true));
$response = 200;
$headers = getallheaders();
$timestamp = time();
$payload = file_get_contents('php://input');
$signature = '';
$hash = base64_encode(hash_hmac('sha256', $payload, $secret, true));
$response = 200;

We use multiple WebHooks in our project and for some stupid reason Xero is the only one for which we need to use a separate file -outside our web root on it's own.
It doesn't matter if the headers values are empty, if it sees a key of any kind it will fail.
I hope this helps.
It doesn't matter if the headers values are empty, if it sees a key of any kind it will fail.
I hope this helps.

I'm trying to post the rest of my code and it won't let me :(

I don't want to see your code. Just move the endpoint somewhere away from your project where things like $_SESSION etc. won't interfere.

Ben, I actually saw your previous comment about having to have a file outside of your project root in order for it to work, but I've tested that as well. I'm still getting the error with ITr pointing to a file in my webroot.

http_response_code($response);
//header("Content-Length: 0");
ob_flush();
flush();
ob_end_clean();
exit;
//header("Content-Length: 0");
ob_flush();
flush();
ob_end_clean();
exit;

I guess that's the problem. I wanted to share my code because my endpoint is completely standalone, and not affected by and project settiings/files/variables.
20 lines of code, no includes, sending an http response, and exiting.
20 lines of code, no includes, sending an http response, and exiting.

The only bit of code it won't let me post here is two if statements that actually figure the correct response code.
Ben can you give an example of what you have that is working correctly for you?
Ben can you give an example of what you have that is working correctly for you?

My webhook is pointing to a file in webroot, and I actually stripped everything out except these few lines:
header_remove ();
http_response_code(200);
ob_flush();
flush();
ob_end_clean();
exit;
And I'm still getting that same error, 'Response contained a body'.
header_remove ();
http_response_code(200);
ob_flush();
flush();
ob_end_clean();
exit;
And I'm still getting that same error, 'Response contained a body'.

At the end of the day we're talking about accounting software that reuses invoice numbers. Who knows why things happen the way they do.

Lol, that may be true, but at the end of the day, I gotta eat and to do that I need to finish my current project :)
I found the answer. There's a defect in PHP 5.6 that will throw a deprecation error when you use:
file_get_contents('php://input');
I found the answer. There's a defect in PHP 5.6 that will throw a deprecation error when you use:
file_get_contents('php://input');

The only solution is to edit p h p . i n i and set:
always_populate_raw_post_data = -1
You can't turn it off by setting error_reporting(0) or by using ini_set() to change that setting.
I discovered this when watching this helpful video, https://devblog.xero.com/lets-play-web-hooky-with-php-34a141dcac0a, and figuring out that it's the same method that I was using and it failed on my system as well.
In the process I also learned something new. I've been a huge fan of ngrok for awhile, but I didn't know until tonight that it has a response/request viewer built-in. (localhost:4040).
always_populate_raw_post_data = -1
You can't turn it off by setting error_reporting(0) or by using ini_set() to change that setting.
I discovered this when watching this helpful video, https://devblog.xero.com/lets-play-web-hooky-with-php-34a141dcac0a, and figuring out that it's the same method that I was using and it failed on my system as well.
In the process I also learned something new. I've been a huge fan of ngrok for awhile, but I didn't know until tonight that it has a response/request viewer built-in. (localhost:4040).

Really?!? I can't type p h p . i n i without the spaces in a post, what year is this?