Amazon API Changes, Bookdata, PHP (Sorry)

August 11, 2009

Warning: deeply dull post ahead. But, we’ve had a lot of discussion about bookdata, APIs, and Amazon on this blog, so it would be remiss of me not to post this.

From August 15th, Amazon requires all API requests to be signed, which to the layman means that you need to add a timestamp, and a ‘signature’, which is a hash of the entire request, and your private Amazon key.

There are a bunch of PHP examples for doing this on the web, but because I had to tweak them all slightly to get them to work, I thought I’d put it out there to be helpful – I’ve just implemented this on bkkeepr and Bookseer and a few other places…


// Build your request string, e.g.
$request = 'Service=AWSECommerceService&'.'AWSAccessKeyId=[YOUR AWS ACCESS KEY]&'.'Timestamp='.gmdate("Y-m-d\TH:i:s\Z").'&Operation=ItemSearch&Title='.$title.'&SearchIndex=Books';

// Encode and sort the request string
$request = str_replace(',','%2C', $request);
$request = str_replace(':','%3A', $request);
$reqarr = explode('&',$request);
$string_to_sign = implode("&", $reqarr);

// Append endpoint
$string_to_sign = "GET\\n/onca/xml\n".$string_to_sign;

// Create signature hash
$signature = urlencode(base64_encode(hash_hmac("sha256", $string_to_sign, '[YOUR AWS PRIVATE KEY]', True)));

// Append signature to original request
$request .= '&Signature='.$signature;

// Append endpoint to original request
$request = ''.$request;

// Make request
Append signature to original request
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_URL, $request);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
$book_data = curl_exec($curl_handle);
return $book_data;

It’s actually pretty simple when you get your head round it, although Amazon has done an atrocious job of helping people make the change. You need to be quite the developer – or, in my case, read piles of unhelpful documentation and a hell of a lot of helpful blogs – to get your head round it, but I hope that helps someone.

Remember, you can make your own changes to the $request string in the example above – don’t forget the Timestamp, it’s important – and change the endpoint from to .com, .fr etc. There’s also a slightly helpful Amazon helper here.

If anyone has questions, I’ll try to help – but not promising anything…


  1. Many thanks for this as I’d been pulling my hair out trying to get Amazon’s web service to work. Note that the book title needs to have any spaces replaced by %20.

    Comment by Rod Page — August 22, 2009 @ 7:02 am

  2. Hi Rod – glad it helped, and thanks, yes – the book title needs to be made safe…

    Comment by James Bridle — August 24, 2009 @ 9:34 am

  3. I tried your code. It works. Thanks so much. Without your code I’m sure I never would’ve gotten my API requests to work. I’m just confused at how and why it works. Amazon (poorly) explains this at:
    It says “The endpoint is not included.”, so I’m totally baffled at this line in your code: $string_to_sign = “GET\\n/onca/xml\n”.$string_to_sign;
    I don’t understand hash_hmac either, but nevermind that. I just wondered if you can explain why you appended that strangely modified endpoint.

    Comment by David — September 20, 2009 @ 6:23 am

  4. Thanks for this very useful tip. I was wondering why in the code should be insert our associate user id .e.g ‘bkseller-20’? The reason I ask is because everytime I insert it in the $request url, I get error message.

    I just can’t work out where it should be insert then.
    Thanks for your help

    Comment by Helen Sam — October 7, 2009 @ 12:46 am

  5. Helen – what are you trying to do? The Associate ID is for linking to Amazon, not using the API – as far as I’m aware…

    Comment by James Bridle — October 7, 2009 @ 10:04 am

  6. Thanks for your comment, James. My bad, I was entering my associate Id incorrectly. It’s now fixed :)

    Great resource you have here.

    Comment by Helen Sam — October 8, 2009 @ 10:55 pm

  7. Thanks buddy.

    Comment by Sinki — November 23, 2009 @ 7:24 pm

  8. Can you tell me how to get the images ? Beacuse in the Xml i am not getting any node for images but previously with amazon api i have done.

    Comment by Sinki — November 23, 2009 @ 7:28 pm

  9. Whether it returns images depends on which response group you’re using:

    You certainly need to ask for at least the Medium group if not the large one to get product images…

    Comment by James Bridle — November 23, 2009 @ 7:49 pm

  10. Thanks for the clarification, it helped alot.
    I already figured out, that i have to replaces spaces with %20.

    But if I’m using German Umlauts (ü,ö,ä), or for example French characters I always get the following response:

    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.

    I tried to encode the stuff with rawurlencode (which works fine for spaces), but as it seems not for other characters.

    Do you have any idea how to solve this?

    Thank you very much

    Comment by Sebastian — December 10, 2009 @ 4:33 pm

Comments are closed. Feel free to email if you have something to say, or leave a trackback from your own site.