Has anyone been able to successfully implement the Amazon Products API in C#?
This is a conversion of the PHP code sample on the scratchpad website.
I get this response:
{"Output":{"__type":"com.amazon.coral.service#InternalFailure","message":null},"Version":"1.0"}
Preferably there should be an SDK to make this easier, however as of 2023 Amazon doesn't seem to offer an SDK for the products API.
public class Program
{
static async Task Main(string[] args)
{
string serviceName = "ProductAdvertisingAPI";
string region = "us-east-1";
string accessKey = "**************";
string secretKey = "**************";
string payload = "{"
+ "\"Keywords\": \"notebook\","
+ "\"PartnerTag\": \"x0d-20\","
+ "\"PartnerType\": \"Associates\","
+ "\"Marketplace\": \"www.amazon.com\""
+ "}";
string host = "webservices.amazon.com";
string uriPath = "/paapi5/searchitems";
AwsV4 awsv4 = new AwsV4(accessKey, secretKey);
awsv4.SetRegionName(region);
awsv4.SetServiceName(serviceName);
awsv4.SetPath(uriPath);
awsv4.SetPayload(payload);
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.SearchItems");
Dictionary<string, string> headers = awsv4.GetHeaders();
using (HttpClient client = new HttpClient())
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"https://{host}{uriPath}");
foreach (var header in headers)
{
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
request.Content = new StringContent(payload, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.SendAsync(request);
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseContent);
}
Console.ReadLine();
}
public class AwsV4
{
private string accessKey = null;
private string secretKey = null;
private string path = null;
private string regionName = null;
private string serviceName = null;
private string httpMethodName = null;
private Dictionary<string, string> queryParameters = new Dictionary<string, string>();
private Dictionary<string, string> awsHeaders = new Dictionary<string, string>();
private string payload = "";
private string HMACAlgorithm = "AWS4-HMAC-SHA256";
private string aws4Request = "aws4_request";
private string strSignedHeader = null;
private string xAmzDate = null;
private string currentDate = null;
public AwsV4(string accessKey, string secretKey)
{
this.accessKey = accessKey;
this.secretKey = secretKey;
this.xAmzDate = GetTimeStamp();
this.currentDate = GetDate();
}
public void SetPath(string path)
{
this.path = path;
}
public void SetServiceName(string serviceName)
{
this.serviceName = serviceName;
}
public void SetRegionName(string regionName)
{
this.regionName = regionName;
}
public void SetPayload(string payload)
{
this.payload = payload;
}
public void SetRequestMethod(string method)
{
this.httpMethodName = method;
}
public void AddHeader(string headerName, string headerValue)
{
this.awsHeaders[headerName] = headerValue;
}
private string PrepareCanonicalRequest()
{
StringBuilder canonicalURL = new StringBuilder();
canonicalURL.Append(httpMethodName).Append("\n");
canonicalURL.Append(path).Append("\n").Append("\n");
string signedHeaders = "";
foreach (var header in awsHeaders)
{
signedHeaders += header.Key + ";";
canonicalURL.Append(header.Key).Append(":").Append(header.Value).Append("\n");
}
canonicalURL.Append("\n");
strSignedHeader = signedHeaders.TrimEnd(';');
canonicalURL.Append(strSignedHeader).Append("\n");
canonicalURL.Append(GenerateHex(payload));
return canonicalURL.ToString();
}
private string PrepareStringToSign(string canonicalURL)
{
StringBuilder stringToSign = new StringBuilder();
stringToSign.Append(HMACAlgorithm).Append("\n");
stringToSign.Append(xAmzDate).Append("\n");
stringToSign.Append(currentDate).Append("/").Append(regionName).Append("/").Append(serviceName).Append("/").Append(aws4Request).Append("\n");
stringToSign.Append(GenerateHex(canonicalURL));
return stringToSign.ToString();
}
private string CalculateSignature(string stringToSign)
{
byte[] signatureKey = GetSignatureKey(secretKey, currentDate, regionName, serviceName);
byte[] signature = HashHMAC(Encoding.UTF8.GetBytes(stringToSign), signatureKey);
string strHexSignature = BitConverter.ToString(signature).Replace("-", "").ToLower();
return strHexSignature;
}
public Dictionary<string, string> GetHeaders()
{
awsHeaders["x-amz-date"] = xAmzDate;
SortedDictionary<string, string> sortedHeaders = new SortedDictionary<string, string>(awsHeaders);
StringBuilder canonicalURL = new StringBuilder(PrepareCanonicalRequest());
string stringToSign = PrepareStringToSign(canonicalURL.ToString());
string signature = CalculateSignature(stringToSign);
awsHeaders["Authorization"] = BuildAuthorizationString(signature);
return awsHeaders;
}
private string BuildAuthorizationString(string strSignature)
{
return HMACAlgorithm + " " + "Credential=" + accessKey + "/" + GetDate() + "/" + regionName + "/" + serviceName + "/" + aws4Request + "," + "SignedHeaders=" + strSignedHeader + "," + "Signature=" + strSignature;
}
private string GenerateHex(string data)
{
using (SHA256 sha256Hash = SHA256.Create())
{
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(data));
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
}
private byte[] GetSignatureKey(string key, string date, string regionName, string serviceName)
{
byte[] kSecret = Encoding.UTF8.GetBytes("AWS4" + key);
byte[] kDate = HashHMAC(Encoding.UTF8.GetBytes(date), kSecret);
byte[] kRegion = HashHMAC(Encoding.UTF8.GetBytes(regionName), kDate);
byte[] kService = HashHMAC(Encoding.UTF8.GetBytes(serviceName), kRegion);
byte[] kSigning = HashHMAC(Encoding.UTF8.GetBytes(aws4Request), kService);
return kSigning;
}
private byte[] HashHMAC(byte[] data, byte[] key)
{
using (HMACSHA256 hmac = new HMACSHA256(key))
{
return hmac.ComputeHash(data);
}
}
private string GetTimeStamp()
{
return DateTime.UtcNow.ToString("yyyyMMdd\\THHmmss\\Z");
}
private string GetDate()
{
return DateTime.UtcNow.ToString("yyyyMMdd");
}
}
}