GetMyFeesEstimate API Amazon vba - excel

I have a problem getting a reasonable answer from Amazon. The problem is only with GetMyFeesEstimate. The other stuff like GetMyPriceForASIN works. I'm trying to get a response with VBA/Excel.
Example Code from Amazon:
https://mws.amazonservices.de/Products/2011-10-01?
FeesEstimateRequestList.FeesEstimateRequest.1.MarketplaceId=A1PA6795UKMFR9
&FeesEstimateRequestList.FeesEstimateRequest.1.IdType=ASIN
&FeesEstimateRequestList.FeesEstimateRequest.1.IdValue=3828934897
&FeesEstimateRequestList.FeesEstimateRequest.1.IsAmazonFulfilled=true
&FeesEstimateRequestList.FeesEstimateRequest.1.Identifier=request1
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.CurrencyCode=EUR
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.Amount=30.00
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.CurrencyCode=EUR
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.Amount=3.99
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsNumber=0
&AWSAccessKeyId=XXXXXXXXXXXXX
&Action=GetMyFeesEstimate
&SellerId=XXXXXXXXXXXXXX
&SignatureMethod=HmacSHA256
&SignatureVersion=2
&Timestamp=2018-01-07T10%3A26%3A27Z&Version=2011-10-01&Signature=bJJJorhyeKwejuddJs6Z%2BVYZZmKtm0CG2GAXTrShyZM%3D
If I try to use this signed request with my data I get the following mistake:
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.
Can someone help me with this?
Here is the Documentation from Amazon.

You haven't shown code on how you are signing the request.
Since you already have been succesful for one API, can you check if you that the decimal values you are using are exactly the same in signing string and POST request?
Sometime excel stores values like 30.0 as 0.3E02 or something like that and this causes the signing string to be different from your post request.
I have used Amazon Scratchpad to create a POST and also to get a guidance on the signing string.
Please go to https://mws.amazonservices.com/scratchpad/index.html
Once you enter the details on the left and click on submit, you can see the Request details and the signing string. If you create the request exactly as specified there and sign exactly as specified there, you shouldnt have a singing issue.
Here is the sample for your request:
POST /Products/2011-10-01?AWSAccessKeyId=
&Action=GetMyFeesEstimate
&SellerId=XXXXXXXXXXXXXX
&SignatureVersion=2
&Timestamp=2018-06-12T04%3A19%3A55Z
&Version=2011-10-01
&Signature=vJLewLVH7FmUD8cpST8dD51GBUJkt6Aj9FADGLoCjNQ%3D
&SignatureMethod=HmacSHA256
&FeesEstimateRequestList.FeesEstimateRequest.1.MarketplaceId=A1PA6795UKMFR9
&FeesEstimateRequestList.FeesEstimateRequest.1.IdType=ASIN
&FeesEstimateRequestList.FeesEstimateRequest.1.IdValue=3828934897
&FeesEstimateRequestList.FeesEstimateRequest.1.IsAmazonFulfilled=true
&FeesEstimateRequestList.FeesEstimateRequest.1.Identifier=request1
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.Amount=30.00
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.CurrencyCode=EUR
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.Amount=3.99
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.CurrencyCode=EUR
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsNumber=0 HTTP/1.1
Host: mws.amazonservices.com
x-amazon-user-agent: AmazonJavascriptScratchpad/1.0 (Language=Javascript)
Content-Type: text/xml
Here is the string to sign.
Note that you have to put CHR(10) for a new line. Do not put VBCRLF in the string.
POST
mws.amazonservices.com
/Products/2011-10-01
AWSAccessKeyId=&Action=GetMyFeesEstimate&FeesEstimateRequestList.FeesEstimateRequest.1.IdType=ASIN&FeesEstimateRequestList.FeesEstimateRequest.1.IdValue=3828934897&FeesEstimateRequestList.FeesEstimateRequest.1.Identifier=request1&FeesEstimateRequestList.FeesEstimateRequest.1.IsAmazonFulfilled=true&FeesEstimateRequestList.FeesEstimateRequest.1.MarketplaceId=A1PA6795UKMFR9&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.Amount=30.00&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.CurrencyCode=EUR&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsNumber=0&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.Amount=3.99&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.CurrencyCode=EUR&SellerId=XXXXXXXXXXXXXX&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2018-06-12T04%3A19%3A55Z&Version=2011-10-01

Related

How to parse and edit XML in TypeScript without converting to JSON

I need to repair an XML file in TypeScript and I cannot find any info on it, since everyone who posts something like this has different needs. I'd like to be pointed in the right direction here.
I have an XML request as shown below. It is autogenerated by node-soap when given JSON. Using the WSDL, node-soap attempts to fill in the namespace prefixes for each property. The problem is, it gets them wrong a lot.
In this example below, q106 should be replaced with hep3.
<soap:Envelope q15="some-good-url" q106="some-good-url-1" q98-"some-good-url-2>
...
<q98:SalesOrderAuditInfo>
<q15:ConfirmedBy xsi:nil="true"></q15:ConfirmedBy>
<q15:ConfirmedDate>0001-01-01T00:00:00</q15:ConfirmedDate>
<q15:CreatedBy>
<q106:ID>103</q106:ID>
<q106:Value>System, System</q106:Value>
</q15:CreatedBy>
<q15:CreatedDate>2022-10-26T00:43:13.413</q15:CreatedDate>
<q15:SalesOrderType>Standard</q15:SalesOrderType>
</q98:SalesOrderAuditInfo>
I know which namespace prefixes are bad because I have a sample request that was supplied to me. It's just XML. It looks like this:
<soap:Envelope hep="some-good-url" hep1="some-good-url-1" hep2-"some-good-url-2 hep3="some-good-url-3">
...
<hep2:SalesOrderAuditInfo>
<hep:ConfirmedBy xsi:nil="true"></hep:ConfirmedBy>
<hep:ConfirmedBy:ConfirmedDate>0</hep:ConfirmedByConfirmedDate>
<hep:CreatedBy>
<hep3:ID>103</hep3:ID>
<hep3:Value>System, System</hep3:Value>
</hep:CreatedBy>
<hep:CreatedDate>0</hep:CreatedDate>
<hep:SalesOrderType>Standard</hep:SalesOrderType>
</hep2:SalesOrderAuditInfo>
Here is the part that really matters. The Sample Request is the entire possible request body. The supplied request (with incorrect namespaces) is a subset of the sample request. I need to loop through each of the elements in the supplied request, and check to make sure the URL of that element matches the URL of the respective element in the sample request.
So in this example, loop through each element of supplied request. Start with SalesOrderAuditInfo. It's namespace URL is some-good-url-2. If we check the Sample Request, we can see that SalesOrderAuditInfo also corresponds to some-good-url-2.
Continue until we hit the ID tag. This has a namespace set to some-good-url-1. If we check the Same ID (inside of CreatedBy, inside of SalesOrderAuditInfo), we can see the namespace should actually be set to some-good-url-3. So we replace q106 with hep3.
I also need to take all of the namespaces defined in the Sample Request Envelope and move them into the supplied request envelope so that this new hep3 will be defined.
At this point, I need to edit the namespace prefix. In this example, q106:ID would be replaced be the string hep3:ID. Same with all of the closing tags.
Which library can I use to accomplish this in XML? Is anyone familiar with node-soap screwing these namespaces up and know of any fix?
I am using node-soap v0.43

Handling of etags in batch request using SAP Cloud SDK

I am trying to carry out a batch request including a create, update and a delete (all are different salesorders). As per this question here which deals with something similar, I have done a get for the items I want to update and delete before I add them to the batch request. I am using the SalesOrder.builder() to prepare the SalesOrder I want to create.
final ErpHttpDestination destination = DestinationAccessor.getDestination(DESTINATION_NAME)
.asHttp().decorate(DefaultErpHttpDestination::new);
final SalesOrderItem salesOrderItem1 = SalesOrderItem.builder().material(material)
.requestedQuantityUnit(requestedQuantityUnit).build();
final SalesOrder salesOrder1 = SalesOrder.builder().distributionChannel(distributionChannel)
.salesOrderType(salesOrderType).salesOrganization(salesOrganization)
.organizationDivision(organizationDivision).soldToParty(soldToParty)
.item(salesOrderItem1).build();
final SalesOrder orderToUpdate = new GetSingleSalesOrderCommand(orderToUpdateID, destination,
new DefaultSalesOrderService()).execute();
orderToUpdate.setSoldToParty(updateSoldToParty);
final SalesOrder orderToDelete = new GetSingleSalesOrderCommand(orderToDeleteID, destination,
new DefaultSalesOrderService()).execute();
SalesOrderServiceBatch service = new DefaultSalesOrderServiceBatch(
new DefaultSalesOrderService());
BatchResponse bRes = service.beginChangeSet().createSalesOrder(salesOrder1).updateSalesOrder(orderToUpdate)
.deleteSalesOrder(orderToDelete).endChangeSet().execute(destination);
I am then logging the BatchResponse and see I am getting a Batch Response Failure:
eTag handling not supported for http method 'POST'
I have searched for this error but can't find any resolution to it. Any ideas?
Thanks.
UPDATE: Increasing the logging to DEBUG I can see the batch request that is being sent and can see that there is an if-match header being added to the create request, which doesn't make sense as it can't match something that doesn't exist yet.
"msg":"--batch_123\r\nContent-Type: multipart/mixed;
boundary=changeset_(changeset number)\r\n\r\n--
changeset_(changeset number)\r\nContent-Type:
application/http\r\nContent-Transfer-Encoding: binary\r\n\r\nPOST
/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder HTTP/1.1\r\nContent-
Length:
193\r\nIf-Match: W/\"datetimeoffset'2020-05-
01T11%3A51%3A16.8631720Z'\"\r\nAccept:
application/json;odata=verbose\r\nContent-Type:......
The I get the error:
Inner Error:
"msg":"batch
responseFailure(com.sap.cloud.sdk.odatav2.connectivity.ODataException:
null: <?xml version=\"1.0\" encoding=\"utf-8\"?><error
xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">
<code>/IWFND/CM_MGW/537</code><message xml:lang=\"en\">eTag handling not
supported for http method 'POST'</message><innererror>...
However, what does work is if I wrap each request in its own changeset e.g.
service
.beginChangeSet().createSalesOrder(order).endChangeSet()
.beginChangeSet().updateSalesOrder(orderToUpdate).endChangeSet()
.beginChangeSet().deleteSalesOrder(orderToDelete).endChangeSet()
.execute(destination);
Edit:
This is fixed as of version 3.25.0.
Initial Answer:
This seems to be a bug. I was able to reproduce this with a different service and the behaviour is the same: The if-match header is incorrectly applied to the POST operation as well.
When debugging it seems like the request is build up correctly with the header only being present on update and delete. However, it seems that when the batch request is serialised to JSON it gets added to all requests.
So until this is fixed the workaround is isolating these operations via change sets, as you already pointed out.
Looks like eTag handling is not supported for your endpoint.
Now you can do the following to omit eTag headers:
orderToUpdate.setVersionIdentifier(null);
orderToDelete.setVersionIdentifier(null);
However I'm not sure how 'POST' fits the error description, because update uses PATCH and delete uses DELETE. The only POST that I expect would be coming from create. But we do not add headers for entity version identifiers (eTag) in OData create operation. If the same error still comes up, please try again without running createSalesOrder(salesOrder1).

Can't seem to find the issue with the requestID parameter for the request header

I am trying to pull data from a REST API that uses a "similar standard to JSON RPC". The params I am passing look right according to the documentation here and here.
The error I am receiving is ...message:"Header missing request ID".... I am unsure what I am missing that would properly declare the requestID.
I have looked at the documentation provided via the API I am trying to pull data from but it's not very helpful considering it's all in PHP and cURL. I am trying to complete this task using python-requests.
getParams = {'method': 'getCustomers', 'params':{'where':'', 'limit': 2}, 'id': 'getCustomers'}
Result:
{"result":null,"error":{"code":102,"message":"Header missing request ID","data":[]},"id":null}
The return result should contain a list of All Customers and their attributes in JSON format.
Turns out there is nothing wrong with the code I am using. There is an issue with the API I am attempting to call.
In my situation, I was getting the same error back and was required to send a X-Request-ID header. I fixed it by adding the following to my headers:
headers = {
'X-Request-ID': str(uuid.uuid1()) # generate GUID based on host & time
...
Note that (for me) the GUID needed to be of a specific format (e.g. matching the Regex ^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$
taken from https://www.geeksforgeeks.org/how-to-validate-guid-globally-unique-identifier-using-regular-expression/). For example, it still gave the same error if I just sent "test".

Amazon Seller Central MWS ListOrders GET request fails with "The request signature we calculated does not match the signature you provided."

I'm trying to make a GET call to pull orders from Amazon, but I keep getting the same signature error. I've googled around and I see that a lot of people appear to have this error, but none of their solutions seem to fix my issue. Any thoughts?
My request code:
$MWS_Timestamp=GetUTCFormattedDateTime(Date(Now_()),'UTC',false); // 2018-10-22T13:51:32Z
$MWS_AccessKey='AKIA****************';
$MWS_ClientSecret='ChOqu*************************';
$MWS_DeveloperID=798*********;
$MWS_SellerID='A3DL**********';
$MWS_MarketPlaceID='ATVP*********';
$MWS_AuthToken='amzn.mws.********-****-****-****-************';
$MWS_Action='ListOrders';
$MWS_RequestString="";
$MWS_RequestString+="AWSAccessKeyId="+UrlEncode($MWS_AccessKey,0);
$MWS_RequestString+="&Action="+UrlEncode("ListOrders",0);
$MWS_RequestString+="&LastUpdatedAfter="+UrlEncode('2018-10-21T00:00:00Z',0);
$MWS_RequestString+="&MarketplaceId.Id.1="+UrlEncode($MWS_MarketPlaceID,0);
$MWS_RequestString+="&SellerId="+UrlEncode($MWS_SellerID,0);
$MWS_RequestString+="&SignatureVersion="+UrlEncode("2",0);
$MWS_RequestString+="&SignatureMethod="+UrlEncode("HmacSHA1",0);
$MWS_RequestString+="&Timestamp="+UrlEncode($MWS_Timestamp,0);
$MWS_RequestString+="&Version=2013-09-01";
$MWS_SignatureString=$MWS_RequestString;
$signature='';
/* Creating signature with CryptoJS
var hmacsha1Data=CryptoJS.HmacSHA1($MWS_SignatureString,$MWS_ClientSecret); //Also tried $MWS_AccessKey with the same results
var base64EncodeData=CryptoJS.enc.Base64.stringify(hmacsha1Data);
$signature=encodeURIComponent(base64EncodeData);
*/
RunScript("<TAG>Scripts/JS-CryptoJS_v3.12</TAG>");
$signature=Replace($signature,"+","%2B");
$signature=Replace($signature,"/","%2F");
$signature=Replace($signature,"=","%3D");
$MWS_Request=$MWS_RequestString+"&Signature="+$signature;
$MWS_URL='https://mws.amazonservices.com/Orders/2013-09-01?'+$MWS_Request;
The Response:
<ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2013-09-01">
<Error>
<Type>Sender</Type>
<Code>SignatureDoesNotMatch</Code>
<Message>
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.
</Message>
</Error>
<RequestID>54d6059b-9aa8-4d4f-a0b8-beb663599b25</RequestID>
</ErrorResponse>
I'm at a loss here as to which part is wrong. I double-checked the credentials, but everything looks good.
These parameters must all be appended in lexical order.
Here is one example where that isn't the case.
$MWS_RequestString+="&SellerId="+UrlEncode($MWS_SellerID,0);
$MWS_RequestString+="&LastUpdatedAfter="+UrlEncode('2018-10-21T00:00:00Z',0);
The order in the actual URL doesn't matter, but if you don't build them in this order then you won't calculate the right signature -- because the service will sort them before calculating the signature it expects you to send.
Also, your signature encoding is wrong.
$signature=Replace($signature,"+","%20")
There should be only 3 possibilities other than A-Z a-z 0-9:
+ becomes %2B
/ becomes %2F
= becomes %3D

Set metadata in REST request to put blob in AZURE

i am able to upload file to azure blob using REST api provided by Azure.
i want to set metadata at the time i am doing request for put blob, when i am setting it into header as shown here i am unble to upload file and getting following exception org.apache.http.client.ClientProtocolException.
from the last line of the code below
HttpPut req = new HttpPut(uri);
req.setHeader("x-ms-blob-type", blobType);
req.setHeader("x-ms-date", date);
req.setHeader("x-ms-version", storageServiceVersion);
req.setHeader("x-ms-meta-Cat", user);
req.setHeader("Authorization", authorizationHeader);
HttpEntity entity = new InputStreamEntity(is,blobLength);
req.setEntity(entity);
HttpResponse response = httpClient.execute(req);
regarding the same, i have two questions.
can setting different metadata, avoid overwriting of file? See my question for the same here
if Yes for first question, how to set metadata in REST request to put blob into Azure?
please help
So a few things are going here.
Regarding the error you're getting, it is because you're not adding your metadata header when calculating authorization header. Please read Constructing the Canonicalized Headers String section here: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx.
Based on this, you would need to change the following line of code (from your blog post)
String canonicalizedHeaders = "x-ms-blob-type:"+blobType+"\nx-ms-date:"+date+"\nx-ms-version:"+storageServiceVersion;
to
String canonicalizedHeaders = "x-ms-blob-type:"+blobType+"\nx-ms-date:"+date+"\nx-ms-meta-cat"+user+"\nx-ms-version:"+storageServiceVersion;
(Note: I have just made these changes in Notepad so they may not work. Please go to the link I mentioned above for correctly creating the canonicalized headers string.
can setting different metadata, avoid overwriting of file?
Not sure what you mean by this. You can update metadata of a blob by performing Set Blob Metadata operation on a blog.

Resources