Setup Amazon Affiliate API with PHP - Product Advertising API 5.0 (2020)
If you want to get started using Amazon's Associates Affiliate API, known as the Product Advertising API 5.0, then this tutorial will walk you through getting your API keys, setting up a PHP script to get the relevant data you need and general understanding of how you can modify the code to suit your own situation.
This tutorial is going to show you how to connect to Amazon's Affiliate API (Product Advertising API) using PHP to obtain product data.
Table Of Contents
- Introduction to the Amazon Affiliate API
- How to find an Amazon Item's ASIN
- How to get Amazon Product Advertising API Keys
- Amazon Affiliate API PHP Tutorial
Introduction to the Amazon Affiliate API
Connecting to Amazon's API is a very powerful way display up-to-date data on various products your customers might be interested in. Amazon Affiliate Sites are some of the most profitable websites on the internet, far surpassing Google Adsense sites.
Amazon's Affiliate API is actually called the Product Advertising API, after being renamed from Amazon Associates Web Service. Using this API, we can lookup specific products on Amazon and obtain their information, such as live price, images, description and seller details.
We'll be using Amazon's Product Advertising API(PA-API) 5.0 to get the latest data. The old Amazon API 4.0 is no longer accessible and will be turning off on March 20th, so best to upgrade as soon as possible. If you've been using 4.0 and want to now use 5.0, check out this migration guide.
This tutorial is going to show you, in the most simplest terms, how to lookup a product. We'll be using PHP's fopen to access the API and extracting the returned data into an array for us to use.
ItemLookup in Product Advertising API 5.0
The PA-API 5.0 offers new ways to lookup data on Amazon products. We still need to use certain operators, but there are now more options available for us. In 5.0 we now use a "payload" which contains a list of all resources we want to get of a product. Currently available are:
Operation | Description |
---|---|
BrowseNodes | Use Amazon BrowseNodes to get sales ranking etc |
Item -> GetVariations | Get variations of the same product; different size, color etc |
Item-> Getitems | Lookup a specific item by amazon ID (ASIN) or ISBN. |
Item -> SearchItems | Search for different items on the Amazon marketplace |
For the purposes of this guide, we'll be using the GetItems operation to get a specific item's details from the marketplace.
How To Find an Amazon Items ASIN
Since we'll be using GetItems, we need to use either the item's amazon ASIN or ISBN (if it's a book) to lookup the item we are trying to find. You can obtain this information by looking up any item on amazon.com and searching for it on the item page. The ASIN is also found in the URL:
https://www.amazon.com/gp/product/B01IG0E1F0/ref=s9u_nwrsa_gw_i1?
The bolded part is the Amazon ASIN.
How to get Amazon Product Advertising API Keys
We have our item details, we know what operation we'll be using and we know the language we will be coding in (PHP!).
The last piece of the puzzle is to get our developer access keys. If you've ever used an API, you'll be familiar with this process.
Product Advertising API sign up is available only to associates who have referred qualified sales and have been accepted into the program.
Unfortnuately, you need to have earned at least some money using your Amazon Associates account before you can access the API.
Just head over to Amazon's Product Adversting API page and sign up to access it. You can use your Amazon account to do this quickly. Next, you'll need to register for a secret key and an access key. This can be done by going to the Manage Your Account section and clicking on the security credentials area.
Amazon Affiliate API PHP Tutorial
The next step is to build our PHP class to use the Amazon PA-API 5.0. Luckily, you can use Amazon's Scratchpad to test the Amazon API and even get useful code snippets that can get your started. These code snippets handled all the important parts of signing requests, updating payloads and other information that if you're in a rush means you don't need to spend hours to get it working.
We'll be using the PHP Code Snippet and modifying it slightly to get us the following product information:
- Product Name
- Product Image
- Product Price
- Product URL
First, let's analyse the Awsv4 class:
/* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ /* Licensed under the Apache License, Version 2.0. */ class AwsV4 { private $accessKey = null; private $secretKey = null; private $path = null; private $regionName = null; private $serviceName = null; private $httpMethodName = null; private $queryParametes = array (); private $awsHeaders = array (); private $payload = ""; private $host = ""; private $partnerTag = ""; private $itemID = ""; private $HMACAlgorithm = "AWS4-HMAC-SHA256"; private $aws4Request = "aws4_request"; private $strSignedHeader = null; private $xAmzDate = null; private $currentDate = null; public $response = null; public function __construct($accessKey, $secretKey) { $this->accessKey = $accessKey; $this->secretKey = $secretKey; $this->xAmzDate = $this->getTimeStamp (); $this->currentDate = $this->getDate (); } function setPath($path) { $this->path = $path; } function setServiceName($serviceName) { $this->serviceName = $serviceName; } function setRegionName($regionName) { $this->regionName = $regionName; } function setPayload() { $payload = "{" ." \"ItemIds\": [" ." \"".$this->itemID."\"" ." ]," ." \"Resources\": [" ." \"Images.Primary.Small\"," ." \"Images.Primary.Medium\"," ." \"Images.Primary.Large\"," ." \"Images.Variants.Small\"," ." \"Images.Variants.Medium\"," ." \"Images.Variants.Large\"," ." \"ItemInfo.ByLineInfo\"," ." \"ItemInfo.ContentInfo\"," ." \"ItemInfo.ContentRating\"," ." \"ItemInfo.Classifications\"," ." \"ItemInfo.ExternalIds\"," ." \"ItemInfo.Features\"," ." \"ItemInfo.ManufactureInfo\"," ." \"ItemInfo.ProductInfo\"," ." \"ItemInfo.TechnicalInfo\"," ." \"ItemInfo.Title\"," ." \"ItemInfo.TradeInInfo\"," ." \"Offers.Listings.Price\"" ." ]," ." \"PartnerTag\": \"".$this->partnerTag."\"," ." \"PartnerType\": \"Associates\"," ." \"Marketplace\": \"www.amazon.com\"" ."}"; $this->payload = $payload; } function setHost($host) { $this->host = $host; } function setPartnerTag($tag) { $this->partnerTag = $tag; } function setItemID($itemID) { $this->itemID = $itemID; } function setRequestMethod($method) { $this->httpMethodName = $method; } function addHeader($headerName, $headerValue) { $this->awsHeaders [$headerName] = $headerValue; } private function prepareCanonicalRequest() { $canonicalURL = ""; $canonicalURL .= $this->httpMethodName . "\n"; $canonicalURL .= $this->path . "\n" . "\n"; $signedHeaders = ''; foreach ( $this->awsHeaders as $key => $value ) { $signedHeaders .= $key . ";"; $canonicalURL .= $key . ":" . $value . "\n"; } $canonicalURL .= "\n"; $this->strSignedHeader = substr ( $signedHeaders, 0, - 1 ); $canonicalURL .= $this->strSignedHeader . "\n"; $canonicalURL .= $this->generateHex ( $this->payload ); return $canonicalURL; } private function prepareStringToSign($canonicalURL) { $stringToSign = ''; $stringToSign .= $this->HMACAlgorithm . "\n"; $stringToSign .= $this->xAmzDate . "\n"; $stringToSign .= $this->currentDate . "/" . $this->regionName . "/" . $this->serviceName . "/" . $this->aws4Request . "\n"; $stringToSign .= $this->generateHex ( $canonicalURL ); return $stringToSign; } private function calculateSignature($stringToSign) { $signatureKey = $this->getSignatureKey ( $this->secretKey, $this->currentDate, $this->regionName, $this->serviceName ); $signature = hash_hmac ( "sha256", $stringToSign, $signatureKey, true ); $strHexSignature = strtolower ( bin2hex ( $signature ) ); return $strHexSignature; } public function getHeaders() { $this->awsHeaders ['x-amz-date'] = $this->xAmzDate; ksort ( $this->awsHeaders ); // Step 1: CREATE A CANONICAL REQUEST $canonicalURL = $this->prepareCanonicalRequest (); // Step 2: CREATE THE STRING TO SIGN $stringToSign = $this->prepareStringToSign ( $canonicalURL ); // Step 3: CALCULATE THE SIGNATURE $signature = $this->calculateSignature ( $stringToSign ); // Step 4: CALCULATE AUTHORIZATION HEADER if ($signature) { $this->awsHeaders ['Authorization'] = $this->buildAuthorizationString ( $signature ); return $this->awsHeaders; } } private function buildAuthorizationString($strSignature) { return $this->HMACAlgorithm . " " . "Credential=" . $this->accessKey . "/" . $this->getDate () . "/" . $this->regionName . "/" . $this->serviceName . "/" . $this->aws4Request . "," . "SignedHeaders=" . $this->strSignedHeader . "," . "Signature=" . $strSignature; } private function generateHex($data) { return strtolower ( bin2hex ( hash ( "sha256", $data, true ) ) ); } private function getSignatureKey($key, $date, $regionName, $serviceName) { $kSecret = "AWS4" . $key; $kDate = hash_hmac ( "sha256", $date, $kSecret, true ); $kRegion = hash_hmac ( "sha256", $regionName, $kDate, true ); $kService = hash_hmac ( "sha256", $serviceName, $kRegion, true ); $kSigning = hash_hmac ( "sha256", $this->aws4Request, $kService, true ); return $kSigning; } private function getTimeStamp() { return gmdate ( "Ymd\THis\Z" ); } private function getDate() { return gmdate ( "Ymd" ); } // Custom stuff public function getResponse() { $headers = $this->getHeaders (); $headerString = ""; foreach ( $headers as $key => $value ) { $headerString .= $key . ': ' . $value . "\r\n"; } $params = array ( 'http' => array ( 'header' => $headerString, 'method' => 'POST', 'content' => $this->payload ) ); $stream = stream_context_create ( $params ); $fp = @fopen ( 'https://'.$this->host.$this->path, 'rb', false, $stream ); if (! $fp) { throw new Exception ( "Exception Occured" ); } $response = @stream_get_contents ( $fp ); if ($response === false) { throw new Exception ( "Exception Occured" ); } $this->response = $response; return $this; } public function get_item_price() { $itemResult = json_decode($this->response); $price = str_replace(".", "", $itemResult->ItemsResult->Items[0]->Offers->Listings[0]->Price->Amount); return $price; } public function get_item_data() { $itemResult = json_decode($this->response); var_dump(str_replace(".", "", $itemResult->ItemsResult->Items[0]->Offers->Listings[0]->Price->Amount)); $i = $itemResult->ItemsResult->Items[0]; $item = new STDclass; $item->detailedPageURL = $i->DetailPageURL; $item->link = "https://www.amazon.com/gp/product/".$this->itemID."/?tag=" . $this->partnerTag; $item->title = $i->ItemInfo->Title->DisplayValue; $item->smallImage = $i->Images->Primary->Small->URL; $item->mediumImage = $i->Images->Primary->Medium->URL; $item->largeImage = $i->Images->Primary->Large->URL; $item->price = $this->get_item_price(); return $item; } } ?>
This Awsv4.php class is a modified one generated by the Amazon Scratchpad; I've updated a few things to make it work for what I need it to do. You'll probably want to customize it yourself so you can modify the lookup code (Since GetItems actually allows you to lookup multiple items at once and we're just using the code to lookup a single item).
So how do we use the class? It's very easy to use:
$awsv4 = new AwsV4 ($amazon_access_key, $amazon_secret_key); $awsv4->setRegionName("us-east-1"); $awsv4->setServiceName("ProductAdvertisingAPI");
First you need to create a new object and add in your Amazon Access Key and Secret Key gotten from your API settings. Then you need to set your region for looking up items on Amazon and also the service you'll be using (ProductAdvertisingAPI).
I added a few custom methods to the class for storing data and streamlining it all:
$awsv4->setPath ($uriPath); $awsv4->setHost($host); $awsv4->setItemID($amazon_id); $awsv4->setPartnerTag($partner_tag); $awsv4->setPayload ();
$uriPath is set to "/paapi5/getitems" which is the Getitems operator we want to use. $host is set to "webservices.amazon.com" since we are using this to lookup product data on Amazon.com. You'll want to change this to the region of your choice.
$amazon_id refers to the ASIN ID of the product you're looking up. $partner_tag is your Amazon Associates partner tag used to keep track of your referrals.
The setPayload method is just a custom function I made so I didn't have to paste the ugly resource list that I need everytime. You can customise this in the scratchpad and get a quick list of data you need very easily. This payload allows me to get the product information I need. You can view it in the class above:
function setPayload() { $payload = "{" ." \"ItemIds\": [" ." \"".$this->itemID."\"" ." ]," ." \"Resources\": [" ." \"Images.Primary.Small\"," ." \"Images.Primary.Medium\"," ." \"Images.Primary.Large\"," ." \"Images.Variants.Small\"," ." \"Images.Variants.Medium\"," ." \"Images.Variants.Large\"," ." \"ItemInfo.ByLineInfo\"," ." \"ItemInfo.ContentInfo\"," ." \"ItemInfo.ContentRating\"," ." \"ItemInfo.Classifications\"," ." \"ItemInfo.ExternalIds\"," ." \"ItemInfo.Features\"," ." \"ItemInfo.ManufactureInfo\"," ." \"ItemInfo.ProductInfo\"," ." \"ItemInfo.TechnicalInfo\"," ." \"ItemInfo.Title\"," ." \"ItemInfo.TradeInInfo\"," ." \"Offers.Listings.Price\"" ." ]," ." \"PartnerTag\": \"".$this->partnerTag."\"," ." \"PartnerType\": \"Associates\"," ." \"Marketplace\": \"www.amazon.com\"" ."}"; $this->payload = $payload; }
Next we need to set the headers that the PA-API 5.0 expects us to have. This is generated automatically for you by the scratchpad:
$awsv4->setRequestMethod ("POST"); $awsv4->addHeader ('content-encoding', 'amz-1.0'); $awsv4->addHeader ('content-type', 'application/json; charset=utf-8'); $awsv4->addHeader ('host', $host); $awsv4->addHeader ('x-amz-target', 'com.amazon.paapi5.v1.ProductAdvertisingAPIv1.GetItems');
The x-amz-target needs to include the operator you're using, in this case its the GetItems operator.
And finally, we then call the methods needed to call the request and get the data we need. I created two custom functions in the class for this:
$product = $awsv4->getResponse()->get_item_data();
$product now contains all the data I need in Object form. Let's look at the code in a bit more detail:
GetResponse is mostly Amazon's Scratchpad code but with a few tweaks:
public function getResponse() { $headers = $this->getHeaders (); $headerString = ""; foreach ( $headers as $key => $value ) { $headerString .= $key . ': ' . $value . "\r\n"; } $params = array ( 'http' => array ( 'header' => $headerString, 'method' => 'POST', 'content' => $this->payload ) ); $stream = stream_context_create ( $params ); $fp = @fopen ( 'https://'.$this->host.$this->path, 'rb', false, $stream ); if (! $fp) { throw new Exception ( "Exception Occured" ); } $response = @stream_get_contents ( $fp ); if ($response === false) { throw new Exception ( "Exception Occured" ); } $this->response = $response; return $this; } public function get_item_price() { $itemResult = json_decode($this->response); $price = str_replace(".", "", $itemResult->ItemsResult->Items[0]->Offers->Listings[0]->Price->Amount); return $price; } public function get_item_data() { $itemResult = json_decode($this->response); var_dump(str_replace(".", "", $itemResult->ItemsResult->Items[0]->Offers->Listings[0]->Price->Amount)); $i = $itemResult->ItemsResult->Items[0]; $item = new STDclass; $item->detailedPageURL = $i->DetailPageURL; $item->link = "https://www.amazon.com/gp/product/".$this->itemID."/?tag=" . $this->partnerTag; $item->title = $i->ItemInfo->Title->DisplayValue; $item->smallImage = $i->Images->Primary->Small->URL; $item->mediumImage = $i->Images->Primary->Medium->URL; $item->largeImage = $i->Images->Primary->Large->URL; $item->price = $this->get_item_price(); return $item; }
That's all there is to it really. I highly recommend looking at the Amazon Scratchpad for customising your own solution. Hopefully this tutorial will help you get started using the latest Amazon API. Using the class in full code:
$host = "webservices.amazon.com"; $uriPath = "/paapi5/getitems"; $awsv4 = new AwsV4 ($amazon_access_key, $amazon_secret_key); $awsv4->setRegionName("us-east-1"); $awsv4->setServiceName("ProductAdvertisingAPI"); $awsv4->setPath ($uriPath); $awsv4->setHost($host); $awsv4->setItemID($amazon_id); $awsv4->setPartnerTag($partner_tag); $awsv4->setPayload (); $awsv4->setRequestMethod ("POST"); $awsv4->addHeader ('content-encoding', 'amz-1.0'); $awsv4->addHeader ('content-type', 'application/json; charset=utf-8'); $awsv4->addHeader ('host', $host); $awsv4->addHeader ('x-amz-target', 'com.amazon.paapi5.v1.ProductAdvertisingAPIv1.GetItems'); $product = $awsv4->getResponse()->get_item_data();
Clive H
I've used Amazon API before and this was a much simplier and faster way of doing things. Thanks for sharing! Now I have a question concerning how you are selecting your amazon products on the page. Do you have a db table with asins and are selecting 4 at random to be displayed? Or are you pulling say 4 from an amazon category and displaying them.
If it is the latter, could you explain how you are doing so. It would be good to pull 4 from a category in amazon say between 2 price ranges that have reviews and possibly a rating range (3.5-5). manually adding asins to a table means always having to check amazon for new products that come in. Automation as much as possbile is ideal. Your thoughts! Thanks
Reply