Accessing Amazon Product Advertising API

Updated: 19th October 2011

In this post we will see how to access the Amazon Product Advertising API from PHP. Amazon has recently changed (from 15th Aug ’09) the authentication mechanism for accessing their API which must now be signed with your Amazon keys. Unsigned requests will be rejected by Amazon. Also now Amazon Associate Tag is required in the query (effective from 25th Oct. 2011). Note that the code uses the hash_hmac() hash function which is only available for PHP versions 5.1.2 and above, so the code will not work for versions below that.

A small example

Below is an example to access the Amazon Product Advertising API using the provided class.

searchProducts("X-Men Origins",
                                       AmazonProductAPI::DVD,
                                       "TITLE");
    }
    catch(Exception $e)
    {
        echo $e->getMessage();
    }
    
    print_r($result);

?>

You can convert the returned xml to json with the following line.

$result = json_encode($result);

The API access class

Given below is the implementation of the class to access the Amazon Product Advertising API. Comments have been removed for brevity, but are included in the source download. Note that only a few access operations are implemented in the class: ItemLookup, ItemSearch; there are more available in the API, a complete list can be found here. It’s just a simple matter of changing some parameters to implement others.

Items->Item->ItemAttributes->Title))
            {
                return ($response);
            }
            else
            {
                throw new Exception("Invalid xml response.");
            }
        }
    }

    private function queryAmazon($parameters)
    {
        return aws_signed_request("com",
                                  $parameters,
                                  $this->public_key,
                                  $this->private_key,
                                  $this->associate_tag);
    }
    
    public function searchProducts($search,$category,$searchType="UPC")
    {
        $allowedTypes = array("UPC", "TITLE", "ARTIST", "KEYWORD");
        $allowedCategories = array("Music", "DVD", "VideoGames");
        
        switch($searchType) 
        {
            case "UPC" :
                $parameters = array("Operation"     => "ItemLookup",
                                    "ItemId"        => $search,
                                    "SearchIndex"   => $category,
                                    "IdType"        => "UPC",
                                    "ResponseGroup" => "Medium");
                            break;
            
            case "TITLE" :
                $parameters = array("Operation"     => "ItemSearch",
                                    "Title"         => $search,
                                    "SearchIndex"   => $category,
                                    "ResponseGroup" => "Medium");
                            break;
        
        }
        
        $xml_response = $this->queryAmazon($parameters);
        
        return $this->verifyXmlResponse($xml_response);

    }

    public function getItemByUpc($upc_code, $product_type)
    {
        $parameters = array("Operation"     => "ItemLookup",
                            "ItemId"        => $upc_code,
                            "SearchIndex"   => $product_type,
                            "IdType"        => "UPC",
                            "ResponseGroup" => "Medium");
                            
        $xml_response = $this->queryAmazon($parameters);
        
        return $this->verifyXmlResponse($xml_response);

    }
    
    public function getItemByAsin($asin_code)
    {
        $parameters = array("Operation"     => "ItemLookup",
                            "ItemId"        => $asin_code,
                            "ResponseGroup" => "Medium");
                            
        $xml_response = $this->queryAmazon($parameters);
        
        return $this->verifyXmlResponse($xml_response);
    }

    public function getItemByKeyword($keyword, $product_type)
    {
        $parameters = array("Operation"   => "ItemSearch",
                            "Keywords"    => $keyword,
                            "SearchIndex" => $product_type);
                            
        $xml_response = $this->queryAmazon($parameters);
        
        return $this->verifyXmlResponse($xml_response);
    }
    
}

?>

Amazon signed request

The above class uses the ‘aws_signed_request’ function to generate the new request signature. Original code is by Ulrich Mierendorff, modified here to use cURL.

$value)
    {
        $param = str_replace("%7E", "~", rawurlencode($param));
        $value = str_replace("%7E", "~", rawurlencode($value));
        $canonicalized_query[] = $param."=".$value;
    }
    
    $canonicalized_query = implode("&", $canonicalized_query);

    $string_to_sign = $method."\n".$host."\n".$uri."\n".
                            $canonicalized_query;
    
    /* calculate the signature using HMAC, SHA256 and base64-encoding */
    $signature = base64_encode(hash_hmac("sha256", 
                                  $string_to_sign, $private_key, True));
    
    /* encode the signature for the request */
    $signature = str_replace("%7E", "~", rawurlencode($signature));
    
    /* create request */
    $request = "http://".$host.$uri."?".$canonicalized_query."&Signature=".$signature;

    /* I prefer using CURL */
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL,$request);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 15);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

    $xml_response = curl_exec($ch);
    
    if ($xml_response === False)
    {
        return False;
    }
    else
    {
        /* parse XML and return a SimpleXML object, if you would
           rather like raw xml then just return the $xml_response.
         */
        $parsed_xml = @simplexml_load_string($xml_response);
        return ($parsed_xml === False) ? False : $parsed_xml;
    }
}
?>
Download Source
Downloads : [downloadcounter(amazonapi)] / File size : [downloadsize(amazonapi)]

135 thoughts to “Accessing Amazon Product Advertising API”

  1. I tried that earlier unsuccessfully.

    Here is what I did:

    amazon_api_class.php

    case “TITLE” : $parameters = array(“Operation” => “ItemSearch”,
    “Title” => $search,
    “SearchIndex” => $category,
    “ResponseGroup” => “Large”);

    break;

    Example.php

    echo “Sales Rank : {$result->Items->Item->SalesRank}”;

    echo “ASIN : {$result->Items->Item->ASIN}”;
    echo “Sales Detail : {$result->Items->Item->EditorialReviews->EditorialReview}”;

    echo “Items->Item->LargeImage->URL . “\” />”;

    Where did go wrong? Thanks.

  2. You need to do the following using the ‘Large’ response group:

    echo $result->Items->Item->CustomerReviews->Review[0]->Content;

    echo $result->Items->Item->EditorialReviews->EditorialReview[0]->Content;

  3. That worked! But I have one last question:

    How did you know the proper way to format the echo string to display the data?

    I cannot find that information in the documentation.

    For instance, there is a “Source” tag in the XML but if I add that in the string, nothing displays.

    Ex: $result->Items->Item->EditorialReviews->EditorialReview[0]->Source->Content;

  4. Just print the $result using

    print_r($result)

    and view the source, this will display the serialized data from which you can get the node names; or in the ‘aws_signed_request.php’ file, after the line
    .
    .

    $xml_response = curl_exec($ch);

    add the following lines:

    print_r($xml_response);
    exit();

    This will display the actual XML returned by Amazon.

  5. Thanks again..The print_r statement browser display was too jumbled to read it clearly but when I viewed the “source” of the webpage, everything became very understandable.

    [CustomerReviews] => SimpleXMLElement Object
    (
    [AverageRating] => 4.5
    [TotalReviews] => 31
    [TotalReviewPages] => 7
    [Review] => Array
    (
    [0] => SimpleXMLElement Object
    (
    [ASIN] => B000000ZML
    [Rating] => 5
    [HelpfulVotes] => 0
    [CustomerId] => A12GGA1DTETD2H
    [Reviewer] => SimpleXMLElement Object

    All I need to do now is figure out how to display the “Add To Cart” button.

    Thanks again..

  6. Thanks for the awesome piece of code that has made my affiliate programme much better.

    I was struggling with the new signature and timestamp requirements until I saw your solution.

    Keep it up and thanks for sharing. Lovely blog BTW 🙂

  7. I was using a foreach loop to generate the query string rather than implode() as above, and noticed that the request was failing with an invalid signature because I had forgotten to rtrim() the last ampersand from the query string.

    Thanks for the code – this was a huge help, and things seem to be working now.

  8. Thanks for sharing your script. I need small help from you. I am working on magazine price comparison site, wherein on comparison page i need to display magazine of amazon. Can i cache amazon records on my db?

  9. Anup, you are not quite clear on your question, but you can cache any Amazon results in your db for latter access, but I’m not sure how long the cache should remain valid. If Amazon updates their db then your cache can go stale.

  10. Hi Sameer,
    I am successfully able to retrieve magazines from the class you developed. Thank you so much.

    But i facing one problem which is:

    I want to retrieve magazine name ‘TIME’. But i am getting output of all magazine result which match Magazine Title ‘TIME’. I need exact match result for Magazine Title. Can you please suggest me solution for same.

    Code Snippet:
    $obj = new AmazonProductAPI();
    $result = $obj->searchProducts(“TIME”, AmazonProductAPI::MAGAZINE, “TITLE”);

    Thanks,
    Anup

  11. Try adding an extra parameter, like the ‘Publisher’ name in the query. The publisher for ‘Time’ magazine is ‘Time Direct Ventures’, so you can add that to the ‘Title’ parameter. So the code in the class would look like this:


    .
    .

    case "TITLE" :
    $parameters = array("Operation" => "ItemSearch",
    "Title" => $search,
    "Publisher" => "Time Direct Ventures",
    "SearchIndex" => $category,
    "ResponseGroup" => "Large");
    .
    .

    Parameter which you can use are given here:

    http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/USSearchIndexParamForItemsearch.html
    #USSearchIndexParamForItemsearch_magazines

  12. Hello Sameer,

    I am trying to get categories of Books to show on my page using amazon api. Code that you provide is good. i m getting perticular book search result but i want to show books sub categories. can u please tell me what changes i have to do in same code?

  13. You need to search with the ‘BrowseNode’ parameter. For example in the ‘amazon_api_class.php’ file you can change the following code:

    .
    .
    case "TITLE" : $parameters = array("Operation" => "ItemSearch",
    "Title" => $search,
    "SearchIndex" => $category,
    "ResponseGroup" => "Large");
    .
    .

    to


    .
    .
    case "TITLE" : $parameters = array("Operation" => "ItemSearch",
    "BrowseNode" => 283155,
    "SearchIndex" => "Books",
    "ResponseGroup" => "BrowseNodes");
    .
    .

    This will return all the subcategories of ‘Books’, with the names and their BrowseNodes.
    The BrowseNode ‘283155’ is that of Books.

    Note: When using BrowseNodes, replace the following line:

    return $this->verifyXmlResponse($xml_response);

    with


    return $xml_response;

    Now you can search for a particular category by using its BrowseNode and some other search criteria, like say keyword.


    .
    .
    case "TITLE" : $parameters = array("Operation" => "ItemSearch",
    "BrowseNode" => 75,
    "Keywords" => $search,
    "SearchIndex" => "Books",
    "ResponseGroup" => "Large");
    .
    .

    The BrowseNode given above (75) is for the ‘Science’ category.

    You can find a list of BrowseNodes here:
    http://www.browsenodes.com

  14. Hi,
    This is Chandra Mouli. Tanikonda.Please let me know how to connect to the Amazon product api from our applicatin.Thanks in advance..

    Regards
    Chandra Mouli Tanikonda

  15. Thanks a lot for this script !! Finally something understandable and WORKING !!

    Do you also have something for creating and managing their distant basket ?

  16. Hello Sameer,

    Can you please tell me how i can integrate remote shopping cart provided by Amazon API? I am trying CartCreate operation but it is not working. Can you please tell me details?

    Thanks…….

  17. Hey Sameer, thanks very much for your class, I’m trying to figure out a good way of caching the results, as only 10 results are returned for each request. I think I have an idea how to do it but I was wondering if you had already fixed this problem?

  18. Firstly thanks very mch for the code – works great!!

    Just in case anyone else is getting the error:

    “The request must contain the parameter Signature.”

    – make sure you haven’t cut and pasted the code from this webpage (better to download at the link above). If you cut and paste from the page this line is corrupted:

    $request = “http://”.$host.$uri.”?”.$canonicalized_query.”
    &Signature=”.$signature;

    should be:

    $request = “http://”.$host.$uri.”?”.$canonicalized_query.”&Signature=”.$signature;

    i.e no newlines in it!

    Tookk me sometime to work out the problem 🙁

  19. Hi Sameer,

    First of all, thanks a million! This code works really well and I was able to integrate these into my wordpress theme’s functions.php and it is currently working fine.

    However, the issue I am having is that when I try to call the search function (along the lines of example.php) at 2 different places on my page, it doesn’t work and also breaks the flow, or execution of the PHP code for my page. I’m not really sure why this is happening, but it might be related to a clashing of variable/objects?

    I don’t know if this makes much sense, but if you have any idea why this might be happening, I would greatly appreciate your thoughts. Thanks a ton.

    Cheers,
    Sudeep

  20. Make sure you are using PHP 5 or greater for your WordPress installation, which probably you would be. Can you be more specific regarding the error your are getting. I don’t think Variable/Object clashes are the reason.

  21. Hi Sameer,

    Scratch that. I just made a separate php file with everything combined and included it in the header using require_once. That works fine. Including the code in functions.php just seemed like asking for trouble. Not quite sure why it wasn’t working, but this way it works perfectly!

    Thanks again for putting this up. I’m surprised how hard it was to find such an example on the Amazon API, considering that it is quite commonly used.

    Cheers,
    Sudeep

  22. Hi Sameer,

    Sorry for the barrage of comments/questions =). One last question I had. I tried looking this up but I couldn’t find anything for sure. Is there a way to query Amazon just for 1 or two items instead of the default 10? I’m wondering if that might help with pageloading speed? I’m worried that if I have 4-5 individual modules searching for a specific keyword/item it might drastically increase page-load times. Do you have any thoughts/comments on this?

    Thanks a ton.

    Cheers,
    Sudeep

  23. Thanks for the quick reply Sameer. Unfortunately I want to display the Average rating for each product, and I believe that this is only possible with the Large Response group. I’ll run some tests to see how much it is affecting page load speeds. Perhaps the best solution would be to use a caching solution like WP-Super Cache, to enhance page load times.

    Cheers,
    Sudeep

  24. Well I must be the only one that cant get it too work 🙁 ive put my keys in and left the script exactly as it is, and I get a few images of a wolverine DVD with stills, a description and loads of XML coding on the screen 🙁

    been trying for months to get amazon api working, this is the closet though, HELP

  25. Well james you do get the xml output if you us the ‘Example.php’ file. comment out the following line in ‘Example.php’.

    print_r($result);

    You can access various details using the object notation. For example to access the Sales rank use the following code:

    $result->Items->Item->SalesRank;

    Same with the other item properties.

  26. oooh! im so dull! thanks sameer, can see my IRON MAN dvd!

    but how do I get people to buy it! i.e basket button? and where are the parameters to show other stuff like cost?

    cant believe it works!

  27. thanks sameer, you have been most helpful, I have no idea how to search for latest releases or anything, does that code go into example.php? I typed iron man 2 into example.php and I got 1 dvd result back, how would I get top ten?

    last queston I promise! 😉

  28. The API by default returns the top 10 results. You can for example access the sales rank of the 9th item using the following:

    $result->Items->Item[8]->SalesRank;

    (The index starts at ‘0’)

    To look at other item properties do a

    print_r($result);

    and then view the source of the page.

  29. Mine only ever returns 1 result, I have no idea how to get the latest top ten xbox games to show for example. I guess this is too complicated for me 🙁

  30. Thanks for the method for getting the top selling items – I’m amazed it’s not a function in the API but there you go.

  31. Great script.

    If you add a pre tag before the print_r it will format your result in a nicer way:

    echo “”;
    print_r($result);
    echo “”;

    Cheers
    Amir

Comments are closed.