Amazon Seller Central - Creating payload hash

Viewed 513

I'm trying to send a request to Amazon Selling Partner API.

I reached a point where I now need to include the marketplaceIds in the request to get past through this error:

{
  "errors": [
    {
     "message": "Missing or invalid request parameters: [MarketplaceIds]",
     "code": "InvalidInput"
    }
  ]
}

However the hash I'm calculating is not the same that the API suggests:

My Full Canonical Request

GET
/orders/v0/orders

host:sellingpartnerapi-eu.amazon.com
user-agent:Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: UAEmdDd-KyWEWcR137UzUzWb1fu3rUgNviHA)
x-amz-access-token:Atza|IwEBIMBLORaPVaVyqdJnWfDF_zMyAccessToken
x-amz-date:2021-03-17T00:39:12.108Z

host;user-agent;x-amz-access-token;x-amz-date
9a34e897d8be214423d5360dbbab5239cb298102312f94bf7d222f91e4770be9

Amazon's Canonical Request

{
  "errors": [
    {
      "message": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

The Canonical String for this request should have been
'GET
/orders/v0/orders

host:sellingpartnerapi-eu.amazon.com
user-agent:Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: UAEmdDd-KyWEWcR137UzUzWb1fu3rUgNviHA)
x-amz-access-token:Atza|IwEBIMBLORaPVaVyqdJnWfDF_zMyAccessToken
x-amz-date:2021-03-17T00:39:12.108Z

host;user-agent;x-amz-access-token;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'

The canonical request is composed of the following values (guide here)

canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash

The component I'm missing is the payload_hash and it could be because of 2 reasons:

  • The content I'm hashing is wrong
  • The way I'm hashing is wrong (or both)

My code:

I want to get my orders from Amazon API (guide here) and the only mandatory value is marketplaceIds:

A list of MarketplaceId values. Used to select orders that were placed in the specified marketplaces.

function GetOrders(){
  var access_token = AccessToken();

  //API variables
  var end_point = 'https://sellingpartnerapi-eu.amazon.com';

  //Credential variables
  var aws_region = "eu-west-1";
  var service = "execute-api";
  var termination_string = "aws4_request";

  //CanonicalRequest = httpRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + HexEncode(Hash(RequestPayload));
  //CanonicalRequest components:
  var httpRequestMethod = 'GET';
  var canonicalURI = '/orders/v0/orders';
  var canonicalQueryString = '';
  var canonicalheaders = 'host:' + "sellingpartnerapi-eu.amazon.com" + '\n' + 'user-agent:' + 'Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: UAEmdDd-KyWEWcR137UzUzWb1fu3rUgNviHA)' + '\n' + 'x-amz-access-token:' + access_token + '\n' + 'x-amz-date:' + isoDate + '\n';
  var signedheaders = 'host;user-agent;x-amz-access-token;x-amz-date';
  
  //Building an object that contains MarketplaceIds array

  var request_parameters =  {
    MarketplaceIds: ["A1PA6795UKMFR9"]
  };
  
  //Hashing the stringify object
  var requestPayloadHashed = digestToHex(JSON.stringify(request_parameters));

  //Building the canonical request
  var canonical_string = httpRequestMethod + '\n' + canonicalURI + '\n' + canonicalQueryString + '\n' + canonicalheaders + '\n' + signedheaders + '\n' + requestPayloadHashed;
  var canonical_signature = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, canonical_string);
  canonical_request = canonical_signature.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");

   //Once the canonical request is completed we continue with the call to the API
   var credential_scope = yearMonthDay + '/' + aws_region + '/' + service + '/' + termination_string;
  var string_to_sign = "AWS4-HMAC-SHA256" + '\n' + isoString + '\n' + credential_scope + '\n' + canonical_request;
  var kSecret = ACCESS_KEY;
  var kDate = Utilities.computeHmacSha256Signature(yearMonthDay, "AWS4" + kSecret);
  var kRegion = Utilities.computeHmacSha256Signature(toBytes(aws_region), kDate);
  var kService = Utilities.computeHmacSha256Signature(toBytes(service), kRegion);
  var kSigning = Utilities.computeHmacSha256Signature(toBytes(termination_string), kService);

  var signature = hex(Utilities.computeHmacSha256Signature(toBytes(string_to_sign), kSigning));
  var options = {
    'method': 'GET',
    'headers': {
      'payload': request_parameters,
      'user-agent': 'Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: UAEmdDd-KyWEWcR137UzUzWb1fu3rUgNviHA)',
      'x-amz-access-token': access_token,
      'x-amz-date': isoDate,
      'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
    },
    'muteHttpExceptions': true
  }
  var getOrders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
  Logger.log(getOrders);
}

I tried to guide myself following this example in Python (the POST call) however I might be missing several things.

0 Answers
Related