We use the Amazon Product Advertising API to do our repricing on their site. For those who don't know it basically lets you interogate the Amazon database without having to do time consuming operations like scraping web pages. It works very well for us, or has. They are now disbanding this API for sellers and moving us to a new API over at their MWS service.
The calls are subtly different as far as I can see. The two obvious differences are that the PA API uses HTTP and GET whereas the MWS is using HTTPS and POST.
I am not entirely sure the examples in the Amazon documentation are correct as they give examples of creating as hash signed URL request. That is the way we used to successfully do it on the PA-API where the GET method was used. But can you do that for POST? I don't think that is possible, although I may be wrong and that is certainly what the examples imply.
Anyway, creating a signed URL doesn't work! So I decided to look along the lines of using some kind of lower level HTTPS POST in Delphi.
I have searched on here and there are several different examples, but I cannot get any of them to work correctly. Some of the examples seem to use INDY 10, unfortunately we are stuck (for compatibility reasons) on INDY 9. I have also looked at the WININET wrapper type functions but I just cannot get a result back other than an exception or errors.
So that is why I am here asking for some help.
How can I make the correctly formatted call to Amazon MWS using Delphi? I have tried examples from pages like:
How to make an HTTPS POST request in Delphi?
etc etc all the ones I could find!
But I get errors back like 'Bad request' (exception).
I have tried using Fiddler (as suggested elsewhere) to look at what is happening but can't quite get my head around it yet (although I can compose a call in it that works!)
So I'm looking for some pointers or some direction on this. I don't really want to go upgrading INDY or adding new libraries. I would just prefer to keep things as they are and use what I have available. We are using D2007.
To give an idea what is required, I need to make this kind of call (the GetServiceStatus
being the most simple):
POST /Products/2011-10-01?AWSAccessKeyId=<ACCESSKEY>
&Action=GetServiceStatus
&SellerId=<SELLERID>
&SignatureVersion=2
&Timestamp=2012-02-14T13%3A26%3A42Z
&Version=2011-10-01
&Signature=dtAvv595blmv%2FnV0h2Yr5bCGzKYXid0hkOuCmZOb3bc%3D
&SignatureMethod=HmacSHA256
To this endpoint:
https://mws.amazonservices.co.uk/Products/2011-10-01
I think my problem is in all the examples I have tried I don't know how to set up the call correctly, which is probably why I get the Bad Request errors.
So, a nice simple solution would be most appreciated!
Documentation links and observations:
This is the developer guide for the API:
This is the particular part of the API we will be using (that replaces the current product advertising API):
The most basic of functions here is the GetServiceStatus function. It takes no parameters. But, it still needs to be authenticated and 'signed' using credentials from Amazon (Seller ID, MWS access key and secret key (for generating a signature). My feeling is that if I can get the most simplest of functions to work then the rest will follow. But the problem of authentification is what makes finding a solution so difficult. There's no test account. And also the timestamp (and therefore the signature for the call) expires and a few minutes.
There is also a 'migration guide':
But this document does contain some errors. For example, the end points are incorrect.
My latest code inc ssl, cookie manager etc:
var
LHTTP : TIdHTTP;
IdSSLIOHandlerSocket : TIdSSLIOHandlerSocket;
IdCookieManager : TIdCookieManager;
LParams : TStringList;
LResponse : string;
begin
IdCookieManager:=TIdCookieManager.Create(self);
IdSSLIOHandlerSocket:=TIdSSLIOHandlerSocket.Create(self);
with IdSSLIOHandlerSocket do begin
SSLOptions.Method := sslvSSLv3;
end;
LHTTP := TIdHTTP.Create(Self);
with LHTTP do begin
CookieManager:=IdCookieManager;
AllowCookies:=true;
IOHandler:=IdSSLIOHandlerSocket;
Request.ContentType:='text/xml';
Port:=443;
HandleRedirects:=true;
Host:='mws.amazonservices.co.uk';
ProtocolVersion:=pv1_1
end;
LParams := TStringList.Create;
try
LParams.Add('AWSAccessKeyId=<ACCESSKEY>');
LParams.Add('Action=GetServiceStatus');
LParams.Add('SellerId=<SELLERID>)');
LParams.Add('SignatureVersion=2');
LParams.Add('Timestamp=2012-02-15T13%3A00%3A07Z');
LParams.Add('Version=2011-10-01');
LParams.Add('Signature=viPlDAbzEBwlTAwq4hNaZi%2Fa1Klf7qIXIP%2BKUsOcJTI%3D');
LParams.Add('SignatureMethod=HmacSHA256');
LResponse:=LHTTP.Post('https://mws.amazonservices.co.uk/Products/2011-10-01?', LParams);
ShowMessage( LResponse );
except
on E: Exception do
ShowMessage('ouch! ' + E.Message );
end;
LHTTP.Free;
IdSSLIOHandlerSocket.Free;
IdCookieManager.Free;
end;
This is based on what Amazon are expecting to receive as per their scratchpad. The user agent at the end is optional and not required and is not part of the signing process:
POST /Products/2011-10-01?AWSAccessKeyId=<ACCESSID>
&Action=GetServiceStatus
&SellerId=<SELLERID>
&SignatureVersion=2
&Timestamp=2012-02-15T13%3A00%3A07Z
&Version=2011-10-01
&Signature=viPlDAbzEBwlTAwq4hNaZi%2Fa1Klf7qIXIP%2BKUsOcJTI%3D
&SignatureMethod=HmacSHA256 HTTP/1.1
Host: mws.amazonservices.co.uk
x-amazon-user-agent: AmazonJavascriptScratchpad/1.0 (Language=Javascript)
Content-Type: text/xml
I have tried to get the information from Fiddler, but it is not showing any traffic from the software but it must be communicating with Amazon to get the '400 bad request' error. Odd.