I migrated from AWS to SP-API without any problems. I only habe a problem with uploading a feed. I try it since weeks in dozen ways. With httpPutRequest and GuzzleHttp\Client, with JSON and XML, with different headers, but I ever get the same error: Header: SignatureDoesNotMatchThe request signature we calculated does not match the signature you provided. Check your key and signing method. I read that most the Content-Type is the problem, and I checked and changed it again and again... My actual code:
function sendFeed($feedURL) {
$method = 'PUT';
//$url = '\SellingPartnerApi\Model\FeedsV20210630\CreateFeedResponse';
$url = $feedURL;
$post2 ="{
<?xml version='1.0' encoding='utf-8' ?>
<AmazonEnvelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='amzn-envelope.xsd'>
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier>xxx</MerchantIdentifier>
</Header>
<MessageType>Inventory</MessageType>
<Message>
<MessageID>1</MessageID>
<OperationType>Update</OperationType>
<Inventory>
<SKU>57832575-1</SKU>
<Quantity>1</Quantity>
</Inventory>
</Message>
</AmazonEnvelope>
}";
$egal = amazonSendFeedRequest($method, $url, $post2);
}
function amazonSendFeedRequest($method, $path, $post) {
// Get access token
$accessToken = getAccessToken();
// Two formats for date used throughout
$date = gmdate('Ymd\THis\Z');
$ymd = gmdate('Ymd');
// Build a canonical request. This is just a highly-structured and
// ordered version of the request you will be making. Each part is
// newline-separated. The number of headers is variable, but this
// uses four headers. Headers must be in alphabetical order.
$canonicalRequest = $method . "\n" // HTTP method
. $path . "\n" // Path component of the URL
. $qs . "\n" // Query string component of the URL (without '?')
. 'host:' . HOST . "\n" // Header
. 'user-agent:' . USER_AGENT . "\n" // Header
. 'x-amz-access-token:' . $accessToken . "\n" // Header
. 'x-amz-date:' . $date . "\n" // Header
. "\n" // A newline is needed here after the headers
. 'host;user-agent;x-amz-access-token;x-amz-date' . "\n" // Header names
. hash('sha256', $post); // Hash of the payload (empty string okay)
// Create signing key, which is hashed four times, each time adding
// more data to the key. Don't ask me why Amazon does it this way.
$signKey = hash_hmac('sha256', $ymd, 'AWS4' . IAM_USER_SECRET, true);
$signKey = hash_hmac('sha256', REGION, $signKey, true);
$signKey = hash_hmac('sha256', 'execute-api', $signKey, true);
$signKey = hash_hmac('sha256', 'aws4_request', $signKey, true);
// Create a String-to-Sign, which indicates the hash that is used and
// some data about the request, including the canonical request from above.
$stringToSign = 'AWS4-HMAC-SHA256' . "\n"
. $date . "\n"
. $ymd . '/' . REGION . '/execute-api/aws4_request' . "\n"
. hash('sha256', $canonicalRequest);
// Sign the string with the key, which will create the signature
// you'll need for the authorization header.
$signature = hash_hmac('sha256', $stringToSign, $signKey);
// Create Authorization header, which is the final step. It does NOT use
// newlines to separate the data; it is all one line, just broken up here
// for easier reading.
$authorization = 'AWS4-HMAC-SHA256 '
. 'Credential=' . IAM_USER_KEY . '/' . $ymd . '/'
. REGION . '/execute-api/aws4_request,'
. 'SignedHeaders=host;user-agent;x-amz-access-token;x-amz-date,'
. 'Signature=' . $signature;
$headers = [];
//$headers[] = 'authorization:' . $authorization;
$headers[] = 'contentType:text/xml; charset=UTF-8';
//$headers[] = 'host:' . HOST;
//$headers[] = 'user-agent:' . USER_AGENT;
//$headers[] = 'x-amz-access-token:' . $accessToken;
//$headers[] = 'x-amz-date:' . $date;
// Run the http request and capture the status code
$status = '';
$result = httpPutRequest($path, $post, $headers, $status);
// Validate the response
if (strpos($result, 'Error:') === 0) exit($result);
if (empty($result)) exit('Error: Empty response');
if ($status != 200 AND $status != 201) exit('Error: Status code ' . $status . ': ' . $result);
if (strpos($result, '{') !== 0) exit('Error: Invalid JSON: ' . $result);
// Decode json and return it
$json = json_decode($result, true);
if (!$json) exit('Error: Problem decoding JSON: ' . $result);
return $json;
}
I would be great if anyone can help me.
With httpPutRequest and GuzzleHttp\Client, with JSON and XML, with different headers