I am trying to make a request to the Amazon SP-API using PHP, but I keep getting an error that my request signature does not match. Although all of the values in my canonical request match up with what the API expected, my hashed value of the canonical request is different. Here is my code:
<?php
$host = 'sellingpartnerapi-na.amazon.com';
$service = 'execute-api';
$region = 'us-east-1';
$accessKey = "aws access key id";
$secretKey = 'aws secret access key';
$accessToken = 'lwa access token';
$requestUrl = 'https://sellingpartnerapi-na.amazon.com';
$httpRequestMethod = 'GET';
$terminationString = 'aws4_request';
$algorithm = 'AWS4-HMAC-SHA256';
$phpAlgorithm = 'sha256';
$signedHeaders = 'content-type;host;x-amz-access-token;x-amz-date';
$canonicalURI = '/';
$canonicalQueryString = '';
$requestHasedPayload = hash($phpAlgorithm, '');
$currentDateTime = new DateTime('UTC');
$reqDate = $currentDateTime->format('Ymd');
$reqDateTime = $currentDateTime->format('Ymd\THis\Z');
// Create canonical request
$canonicalRequest = array();
$canonicalRequest[] = $httpRequestMethod;
$canonicalRequest[] = $canonicalURI;
$canonicalRequest[] = 'content-type:application/json';
$canonicalRequest[] = 'host:sellingpartnerapi-na.amazon.com';
$canonicalRequest[] = 'x-amz-access-token:' . $accessToken;
$canonicalRequest[] = 'x-amz-date:' . $reqDateTime . "\n";
$canonicalRequest[] = rawurlencode($signedHeaders);
$canonicalRequest[] = $canonicalQueryString;
$canonicalRequest[] = $requestHasedPayload;
$requestCanonicalRequest = implode("\n", $canonicalRequest);
$requestHasedCanonicalRequest = hash($phpAlgorithm, utf8_encode($requestCanonicalRequest));
// Create signing key
$kSecret = $secretKey;
$kDate = hash_hmac($phpAlgorithm, $reqDate, 'AWS4' . $kSecret, true);
$kRegion = hash_hmac($phpAlgorithm, $region, $kDate, true);
$kService = hash_hmac($phpAlgorithm, $service, $kRegion, true);
$kSigning = hash_hmac($phpAlgorithm, $terminationString, $kService, true);
// Create scope
$credentialScope = array();
$credentialScope[] = $reqDate;
$credentialScope[] = $region;
$credentialScope[] = $service;
$credentialScope[] = $terminationString;
$credentialScopeStr = implode('/', $credentialScope);
// Create string to sign
$stringToSign = array();
$stringToSign[] = $algorithm;
$stringToSign[] = $reqDateTime;
$stringToSign[] = $credentialScopeStr;
$stringToSign[] = $requestHasedCanonicalRequest;
$stringToSignStr = implode("\n", $stringToSign);
// Create signature
$signature = hash_hmac($phpAlgorithm, $stringToSignStr, $kSigning);
// Create authorization header
$authorizationHeader = array();
$authorizationHeader[] = 'Credential=' . $accessKey . '/' . $credentialScopeStr;
$authorizationHeader[] = 'SignedHeaders=' . $signedHeaders;
$authorizationHeader[] = 'Signature=' . ($signature);
$authorizationHeaderStr = $algorithm . ' ' . implode(', ', $authorizationHeader);
// Request headers
$headers = array();
$headers[] = 'authorization:'. $authorizationHeaderStr;
$headers[] = 'content-type: application/json';
$headers[] = 'host: ' . $host;
$headers[] = 'x-amz-date: ' . $reqDateTime;
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $requestUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_POST => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $httpRequestMethod,
CURLOPT_VERBOSE => 0,
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_HEADER => false,
CURLINFO_HEADER_OUT=>true,
CURLOPT_HTTPHEADER => $headers,
));
$response = curl_exec($curl);
$err = curl_error($curl);
$responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($err) {
echo "<h5>Error:" . $responseCode . "</h5>";
echo "<pre>";
echo $err;
echo "</pre>";
} else {
echo "<h5>Response:" . $responseCode . "</h5>";
echo "<pre>";
echo $response;
echo "</pre>";
}
And if you know a good resource for using the SP-API with php can you please share. The docs are very vague.
Thanks