I’m trying to submit a SubmitFeed
request to Amazon Marketplace, but when I submit the request I get the following error:
the Content-MD5 HTTP header you passed for your feed did not match the Content-MD5 we calculated for your feed
So I tested the request on the Amazon Marketplace Scratchpad. I add my XML to the body, and the headers, and it generates the following MD5 hash:
1db3b177e743dc8c0df4dc9eb5c1cbcf
But there’s also a Content-MD5 (Base64)
header, with this value:
HbOxd+dD3IwN9NyetcHLzw==
And it appears to be that value that’s actually sent to Amazon
MWS as the Content-MD5
HTTP header, not the raw MD5 hash.
I’ve checked my PHP script and it’s generating the raw MD5 hash correctly, as when I wrap my XML string in the md5
function (md5($xml)
) I get the same raw MD5 hash that Amazon generates. But if I then wrap that in the base64_encode
function, I get a totally different value as to what Amazon lists for the Content-MD5 (Base64) value.
So far, I’ve tried wrapping the following in the base64_encode
function:
But none yield the same value as Amazon’s Content-MD5 (Base64) value.
So what exactly is Amazon Base64-encoding to get that value? I’ve tried decoding the value, but just got a load of random characters that appears to be an encoding issue, so I can’t see the raw string that Amazon’s encoding to point me in the right direction.
Any guidance on this would be appreciated.
Found the solution. I decided to look at the documentation for the md5
function and found there was a second parameter to get the raw output of the function, which is false
by default. So, I decided to set that flag to true
instead and Base64-encode the result of that call.
Voilà! I got the same Base64 value as Amazon!
Using Guzzle, this is what I’m sending to Amazon and I’m now getting successful responses:
$xml = trim($xml);
// For some reason, the time my PHP script is sending is about 20 minutes out
// from my system time. This fixes that.
$timestamp = gmdate('c', time() + 1200);
$url = 'https://mws.amazonservices.co.uk/';
$parameters = [
'Action' => 'SubmitFeed',
'AWSAccessKeyId' => '#MY_ACCESS_KEY_ID#',
'FeedType' => '_POST_PRODUCT_DATA_',
'MarketplaceIdList.Id.1' => 'A1F83G8C2ARO7P', # UK marketplace ID
'Merchant' => '#MY_SELLER_ID#',
'PurgeAndReplace' => 'false',
'SignatureMethod' => 'HmacSHA256',
'SignatureVersion' => '2',
'Timestamp' => $timestamp,
'Version' => '2009-01-01',
];
/**
* Custom class that generates signature for request.
*
* @see http://stackoverflow.com/a/29724063/102205
*/
$signature = new Signature($url, $parameters, '#MY_SECRET_ACCESS_KEY#');
$parameters['Signature'] = (string) $signature;
try {
$response = $this->client->post($url, [
'headers' => [
'Content-MD5' => base64_encode(md5($xml, true)),
'User-Agent' => '#MY_USER_AGENT_STRING#',
],
'query' => $parameters,
'body' => $xml,
]);
} catch (\GuzzleHttp\Exception\ClientException $e) {
$response = $e->getResponse();
}
return $response->xml();
Hope this helps someone else!