Blog
The uncooperative beast that is the Amazon MWS API
If you're reading this, there is a decent chance you have stumbled upon this page in the dark dungeons of Google. Likely you are frustrated to your bones with the Amazon Marketplace Webservice API, you have tirelessly exhausted every Stack Overflow thread there is to find on the topic, and you're having vivid nightmares about the SignatureDoesNotMatch error response that you have been staring at for hours, if not days.
Probably you're having vivid nightmares about the SignatureDoesNotMatch error response that have been staring at for hours, if not days.
The good news is, you're not alone. In my search for the dark truth, I have encountered many brave souls on similar quests to conquer the uncooperative beast that is the Amazon MWS API, and chances are you have too. Every now and then, there shines a shimmer of hope from some far away blog post, or deserted forum thread when someone actually proves that it is possible. Briefly, you gain enthusiasm as you try to mimic their solution, but ever so brutally you are brought back to reality: SIGNATUREDOESNOTMATCH. Fuck me.
Still, I am always grateful for someone who takes the time to share their solution, for it may only take a couple of minutes, it may save someone else hours and hours of frustration. So - with a combination of pride for finally completing my mission and a fair bit of embarresment that ten minutes ago I was literally cheering, by myself, in front of my computer, because of an XML ListOrderResponse - here's mine.
So, with a fair bit of embarresment that ten minutes ago I was literally cheering, by myself, in front of my computer, because of an XML ListOrderResponse, here's mine.
I'm building an automatic connection between my e-commerce store and several marketplaces, among which Amazon . Therefore my initial goal was to make even just one succesfull call to the MWS API, from my PHP application, without using Amazon\'s beast of an SDK. Why not just use their SDK? Check out this Medium Post by Sean Clark for a perfect explanation.
Using the Amazon MWS Scratchpad, I could make the calls with my authentication keys (make sure you use the scratchpad on the same tld as the marketplace you are using!), and the second tab nicely shows what request you're actually making and what string you are using to generate the signature . So all we have to do is just mimic that request and we're good to go. Right? Well, for me that turned out to be a bigger illusion than Santa Claus and babies coming from boxes of spinach together (yes, my parents actually told me that).
The first ten or so tries on my own all gave me SignatureDoesNotMatch errors. Oh well, we just got started. Then I started spending hours digging through the Amazon SDK for reference, reading several helpful/comforting threads (e.g., this one and this one), and dozens of people tell me to double-check my freaking acces key (OMG, THANK YOU SO MUCH, BUT I HAPPENED TO HAVE CHECKED THAT 29862987542 TIMES ALREADY). I found out that you have to be super careful in
- how you SORT the paremeters you're sending < br>
- uksort($parameters, 'strcmp');
- how you ENCODE certain parts of the query < br>
- encode the whole sorted parameters array with < br>
$query = http_build_query($sorted_parameters, '', '&',
PHP_QUERY_RFC3986);
before you generate the signature - use
$signature = urlencode(base64_encode(hash_hmac('sha256', $query, $secret_key, true)));
to generate and encode your signature - attach the < b>$signature as the last query parameter without further encoding to your < b>$query string .
- encode the whole sorted parameters array with < br>
$query = http_build_query($sorted_parameters, '', '&',
PHP_QUERY_RFC3986);
This seemed to work well, as I was able to exactly mimic the signatures generated by the scratchpad . However, I was still staring at that horrific SignatureDoesNotMatch error with every single request . I started to hardcode the timestamps from scratchpad into my own code, mirrored the exact order of the query parameters, and freaking copy pasted my own request string and the one from scratch pad into a text comparison tool, only to find out that they were EXACTLY IDENTICAL. Still, no luck.
At this point I am so frustrated I want to just curl up like a baby, and think about butterflies for a while.
At this point I am so frustrated I want to just curl up like a baby, and think about butterflies for a while. I'm about to close my 100 browser tabs as my eye falls on this post, which for the first time pointed to HTTP headers and the specific execution of the request as the reason for the SignatureDoesNotMatch error, even though the signature was right. Now this post dealt with Python and the answer wasn't directly usable, but by diverting my attention to the HTTP headers, it still quickly led to the solution.
After a couple of minutes of playing around with the curl options, a miracle happened the likes of which I may not see again until the birth of my firstborn child (especially if he or she comes from a spinach box). IT GOT THROUGH.
I deduced it to a single Curl Option that seems to make the difference between glory and misery: curl_setopt($curl, CURLOPT_POST, true);. If you want to have the entire working PHP script(which is really only a few dozen lines), just shoot me a message.
Now I suppose I could have deduced that it should be a POST request from the string that is used to sign the signature(even though we are not actually POSTING anything), and I suppose I could be forgiving about the ErrorResponse pointing in the wrong direction, but where's the fun in that?
Instead, I'd rather end with saying that working with anything from Amazon has been the absolute worst experience in my, admittedly inexperienced, developer life. I can only hope that this post will help lighten the pain for even just one brave soldier out there, for if we developers unite, even the most uncooperative of beasts can be conquered.