amzn / selling-partner-api-models

This repository contains OpenAPI models for developers to use when developing software to call Selling Partner APIs.
Apache License 2.0
580 stars 730 forks source link

C# working code examples #31

Closed smithburger closed 1 year ago

smithburger commented 3 years ago

Are there any C# code examples that work as a test by just replacing the credentials? Something simple like get Purchase Order information? I am trying to work off the C# client library and other documentation and am completely lost. The Java documentation is a lot more fleshed out. With C# I can't get past step one.

The code in the readme is incomplete on it's own. As far as I can tell it presumes some type of previous knowledge to get working.

tenitre commented 3 years ago

Hi

Not sure you have went through this process to create your application:
https://github.com/amzn/selling-partner-api-docs/blob/main/guides/developer-guide/SellingPartnerApiDeveloperGuide.md

After your are done with above, then you can follow these steps for getting your orders:

Step 1: Make sure you self auth your app in seller central. and click Generate Token to get your refresh token.

Step 2: Make sure you download the credentials of the user (AWS key and secret) you created in above documentation

Step 3: Go ahead and download this: https://github.com/amzn/selling-partner-api-models/tree/main/clients/sellingpartner-api-aa-csharp

IMPORTANT NOTE: These are R&D examples/codes and code, and there is no guarantee that it will work for you or anybody else.. I am still in learning and wanted to share my experience

Step 4: Add new console app and then add Amazon.SellingPartnerAPIAA to console app

Step 5: Setup your request

var resource = $"/orders/v0/orders"; IRestRequest restRequest = new RestRequest(resource, Method.GET);

        restRequest.AddParameter("MarketplaceIds", MARKETPLACE_ID, ParameterType.QueryString);
        restRequest.AddParameter("CreatedAfter", DateTime.UtcNow.AddDays(-5).ToString("yyyy-MM-dd"), ParameterType.QueryString);

Step 6: The most important step, ppl (like me) spent days to figure out how to that... Create two functions to sign your app with your access token and your AWS keys

private static IRestRequest SignWithAccessToken(IRestRequest restRequest, string clientId, string clientSecret, string refreshToken) { var lwaAuthorizationCredentials = new LWAAuthorizationCredentials { ClientId = clientId, ClientSecret = clientSecret, Endpoint = new Uri("https://api.amazon.com/auth/o2/token"), RefreshToken = refreshToken, };

        return new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restRequest);
    }

and this is for your AWS keys

Note1: roleARN This is the role IRN you created with your app (refer the first document) Note2: The Amazon documents are missing (surprised, surprised) steps. This AssumeRole call is very important otherwise you will keep getting Forbidden

private static IRestRequest SignWithSTSKeysAndSecurityTokenn(IRestRequest restRequest, string host, string roleARN, string accessKey, string secretKey) { AssumeRoleResponse response1 = null; using (var STSClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey, RegionEndpoint.USEast1)) { var req = new AssumeRoleRequest() { RoleArn = roleARN, DurationSeconds = 950, //put anything you want here RoleSessionName = Guid.NewGuid().ToString() };

            response1 = STSClient.AssumeRoleAsync(req, new CancellationToken()).Result;
        }

        //auth step 3
        var awsAuthenticationCredentials = new AWSAuthenticationCredentials
        {
            AccessKeyId = response1.Credentials.AccessKeyId,
            SecretKey = response1.Credentials.SecretAccessKey,
            Region = "us-east-1"
        };

        restRequest.AddHeader("x-amz-security-token", response1.Credentials.SessionToken);

        return new AWSSigV4Signer(awsAuthenticationCredentials)
                        .Sign(restRequest, host);
    }

Now sign your request:

create some class like that and fill it wit your info

public class SellerAPICredentials { public string ClientId { get; set; } public string ClientSecret { get; set; } public string RefreshToken { get; set; } public string AWSKey { get; set; } public string AWSSecret { get; set; } public string RoleARN { get; set; } }

Then call these functions to sign your request

restRequest = SignWithAccessToken(restRequest, credentials.ClientId, credentials.ClientSecret, credentials.RefreshToken);

restRequest = SignWithSTSKeysAndSecurityTokenn(restRequest, Client.BaseUrl.Host, credentials.RoleARN, credentials.AWSKey, credentials.AWSSecret, overrideHost);

Step 5: Finally use your request to call

var client = new RestClient("https://sellingpartnerapi-na.amazon.com"); var response = client.Execute(restRequest);

Good luck!

Oguz

smithburger commented 3 years ago

@tenitre The entire AWS user access, role, user ARN, STS stuff is wild for someone who has never done it. So many moving parts. I am pretty sure I did it correctly and our application is authorized by Amazon for our vendor central account but I am still getting a forbidden error. For what it is worth below is the code in it's entirety.

I appreciate you responding and giving some help. I presume my issue at this point has to do with IAM or the application authorization process and I would need Amazon customer service to respond to a ticket some time in the next year to move forward. If you notice any issues below let me know. If I figure anything out I will post it here as well so everyone can see.


using Amazon;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using Amazon.SellingPartnerAPIAA;
using RestSharp;
using System;
using System.Threading;

namespace amazon_df_scratchpad
{
    class Program
    {
        static void Main(string[] args)
        {
            var resource = $"/vendor/directFulfillment/orders/v1/purchaseOrders";
            IRestRequest restRequest = new RestRequest(resource, Method.GET);

            restRequest.AddParameter("createdAfter", DateTime.UtcNow.AddDays(-5).ToString("yyyy-MM-dd"), ParameterType.QueryString);
            restRequest.AddParameter("createdBefore", DateTime.UtcNow.ToString("yyyy-MM-dd"), ParameterType.QueryString);

            var client = new RestClient("https://sellingpartnerapi-na.amazon.com");

            var credentials = new SellerAPICredentials();
            restRequest = SignWithAccessToken(restRequest, credentials.ClientId, credentials.ClientSecret, credentials.RefreshToken);

            restRequest = SignWithSTSKeysAndSecurityTokenn(restRequest, client.BaseUrl.Host, credentials.RoleARN, credentials.AWSKey, credentials.AWSSecret);

            var response = client.Execute(restRequest);

            Console.WriteLine("");
        }

        private static IRestRequest SignWithAccessToken(IRestRequest restRequest, string clientId, string clientSecret, string refreshToken)
        {
            var lwaAuthorizationCredentials = new LWAAuthorizationCredentials
            {
                ClientId = clientId,
                ClientSecret = clientSecret,
                Endpoint = new Uri("https://api.amazon.com/auth/o2/token"),
                RefreshToken = refreshToken,
            };

            return new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restRequest);
        }

        private static IRestRequest SignWithSTSKeysAndSecurityTokenn(IRestRequest restRequest, string host, string roleARN, string accessKey, string secretKey)
        {
            AssumeRoleResponse response1 = null;
            using (var STSClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey, RegionEndpoint.USEast1))
            {
                var req = new AssumeRoleRequest()
                {
                    RoleArn = roleARN,
                    DurationSeconds = 950, //put anything you want here
                    RoleSessionName = Guid.NewGuid().ToString()
                };

                response1 = STSClient.AssumeRoleAsync(req, new CancellationToken()).Result;
            }

            //auth step 3
            var awsAuthenticationCredentials = new AWSAuthenticationCredentials
            {
                AccessKeyId = response1.Credentials.AccessKeyId,
                SecretKey = response1.Credentials.SecretAccessKey,
                Region = "us-east-1"
            };

            restRequest.AddHeader("x-amz-security-token", response1.Credentials.SessionToken);

            return new AWSSigV4Signer(awsAuthenticationCredentials)
                            .Sign(restRequest, host);
        }
    }

    public class SellerAPICredentials
    {
        public string ClientId = xxxxxxxxxxxxxxxxxxx;
        public string ClientSecret = xxxxxxxxxxxxxxxxxxx;
        public string RefreshToken = xxxxxxxxxxxxxxxxxxx;
        public string AWSKey = xxxxxxxxxxxxxxxxxxx;
        public string AWSSecret = xxxxxxxxxxxxxxxxxxx;
        public string RoleARN = xxxxxxxxxxxxxxxxxxx;
    }
}
`
tenitre commented 3 years ago

Hey @smithburger

your code works just fine... First I tried it with my credentials for this endpoint (/vendor/directFulfillment/orders/v1/purchaseOrders) and I also got Forbidden, then I tried to hit this endpoint

var resource = $"/orders/v0/orders";

It worked just fine... So I think there is something wrong with your request parameters.

Can you also let me know where this (/vendor/directFulfillment/orders/v1/purchaseOrders) endpoint? I never used it before

tenitre commented 3 years ago

BTW the weird thing is when you have wrong param names or values etc. (especially datetime) instead of getting badrequest, you usually get this forbidden error.

Another note that make sure to use role ARN, not user ARN

smithburger commented 3 years ago

Hey @smithburger

your code works just fine... First I tried it with my credentials for this endpoint (/vendor/directFulfillment/orders/v1/purchaseOrders) and I also got Forbidden, then I tried to hit this endpoint

var resource = $"/orders/v0/orders";

It worked just fine... So I think there is something wrong with your request parameters.

Can you also let me know where this (/vendor/directFulfillment/orders/v1/purchaseOrders) endpoint? I never used it before

We are a Direct Fulfillment vendor with Amazon. When you buy our products on Amazon it is sold under the Amazon name. This is not normal 3PP access. The URL I used is the API end point for that call. The SP-API is the same though.

I am guessing our issue is with some IAM policy or ARN somewhere. I did make sure to use the Role ARN in the app. I made the User mistake then fixed it. Went from getting an error about sig not matching to just forbidden. I will open a case with Amazon and see what they say. Hopefully it doesn't take 60 days for them to respond this time.

tenitre commented 3 years ago

Yes you are right... It should be your policy, I recommend you open a support ticket on seller central, but let me tell you this, you need to tell them several times that you are opening the ticket for SP API... After that they will escalate the issue to level2, then you will get your answer.. This is exactly what happened in my case regarding my feeds getting cancelled issue..

Good luck

antonycartwright commented 3 years ago

This is crrrrrrrrrrrazy!

I've been working on this for almost a week and I've not been able to retrieve anything from Amazon other than an access code.

Since your @smithburger code has been tested and worked for @tenitre, I've abandoned mine and adopted yours.

However, I still get the same error with yours which is "The request signature we calculated does not match the signature you provided.". I've worked on this project for 12.5 hrs today and haven't really got anywhere!

The thing is that it's so close. If I remove a parameter, it knows and tells me about it. It's close!

I've changed the DLL slightly as I've found that X-Amz-Date is apparently supposed to be lower case. Also put it back and I still get the same error.

I'm stuck....

rogersv commented 3 years ago

This is crrrrrrrrrrrazy!

I've been working on this for almost a week and I've not been able to retrieve anything from Amazon other than an access code.

Since your @smithburger code has been tested and worked for @tenitre, I've abandoned mine and adopted yours.

However, I still get the same error with yours which is "The request signature we calculated does not match the signature you provided.". I've worked on this project for 12.5 hrs today and haven't really got anywhere!

The thing is that it's so close. If I remove a parameter, it knows and tells me about it. It's close!

I've changed the DLL slightly as I've found that X-Amz-Date is apparently supposed to be lower case. Also put it back and I still get the same error.

I'm stuck....

Share a sample of your request. One guess is that the problem is the query parameters since they need a special encoding but it is hard to know without seeing the request.

antonycartwright commented 3 years ago

Hi everyone,

I've done a lot of diagnostics and I can see the problem - ish!

This is my request (tokens are correct):

GET /orders/v0/orders createdAfter=2020-11-28&MarketplaceIds=A1F83G8C2ARO7P host:sellingpartnerapi-eu.amazon.com x-amz-access-token:[Atza|token] x-amz-date:20201212T115219Z x-amz-security-token:[token]

host;x-amz-access-token;x-amz-date;x-amz-security-token e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Signed AWS4-HMAC-SHA256 20201212T115219Z 20201212/eu-west-1/execute-api/aws4_request cc7b50fe0ec2c6c157959a3dbaa6aca5411ea2d4d19e4989666e2867fc879c4d

The Canonical String for this request should have been

GET /orders/v0/orders MarketplaceIds=A1F83G8C2ARO7P&createdAfter=2020-11-28 host:sellingpartnerapi-eu.amazon.com x-amz-access-token:[Atza|token] x-amz-date:20201212T115219Z x-amz-security-token:[token]

host;x-amz-access-token;x-amz-date;x-amz-security-token e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

The String-to-Sign should have been AWS4-HMAC-SHA256 20201212T115219Z 20201212/eu-west-1/execute-api/aws4_request 55da72cdf7472117ec97337419681da54838ca4f4dd4e26cc98e60d6713ce959

The marketplace id and date seems to be mixed around? The hashed string to sign should be correct as the string is correct!?

antonycartwright commented 3 years ago

Swap the params around and it says:

The Canonical String for this request should have been 'GET /orders/v0/orders CreatedAfter=2020-11-28&MarketplaceIds=A1F83G8C2ARO7P

antonycartwright commented 3 years ago

I resolved this "The request signature we calculated does not match the signature you provided." by fixing the case sensitivity of the parameter names.

jason1004 commented 3 years ago

不错👍

massimobranca commented 3 years ago

using the code provided by smithburger, but at line response1 = STSClient.AssumeRoleAsync(req).Result; get this error: Task does not contains a definition of Result. any idea?

sapnasaini commented 3 years ago

@smithburger Did you able to resolve the signature issue? I am stuck while calling the AmazonFullfillment SP-API endpoint.please help if you found the issue.

smithburger commented 3 years ago

@smithburger Did you able to resolve the signature issue? I am stuck while calling the AmazonFullfillment SP-API endpoint.please help if you found the issue.

Not directly. Amazon CS finally got back to me after 45 days asking for all my request info which I passed on. Their response to that made it seem like my AWS credentials are not correct. I asked them for help and it has been 30+ days again. Amazon CS is awful. I don't want to nuke all my credentials and start from scratch because I don't know how long a new approval would take.

They never said my request was bad though. So I think my code from above should work.

devachamanthi-coder commented 3 years ago

I resolved this "The request signature we calculated does not match the signature you provided." by fixing the case sensitivity of the parameter names.

devachamanthi-coder commented 3 years ago

Hello @antonycartwright - May I know what exactly the parameter name you modified to fix the case sensitivity and do you mind pasting part of the code here? I am able to successfully make calls to getReports resource, however, using the same code, I am having issues while trying to createReport using POST method. I am getting the error "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....The String-to-Sign should have been 'AWS4-HMAC-SHA256.. etc"

leo1695 commented 3 years ago

Hello ,

How can i find the class AmazonSecurityTokenServiceClient and STSAssumeRoleSessionCredentialsProvider ? In which sdk ?

tenitre commented 3 years ago

Hi @leo1695

Not sure what is that class but here is how I use Assume Role in SP API:

using (var STSClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey, RegionEndpoint.USEast1)) { var req = new AssumeRoleRequest() { RoleArn = roleARN, DurationSeconds = 950, RoleSessionName = Guid.NewGuid().ToString() };

            assumeRoleResponse = STSClient.AssumeRoleAsync(req, new CancellationToken()).Result;
        }

You can find these classes in this nuget package:

.nuget\packages\awssdk.securitytoken\3.5.1.22\lib\netcoreapp3.1\AWSSDK.SecurityToken.dll

leo1695 commented 3 years ago

Hi, @tenitre When i call the STSClient.AssumeRoleAsync , i get the response : "user XXX is not authorized to perform: sts:AssumeRole on resource XXX" , so I cannot use this method.

I have call the sp api ok with use the https://github.com/amzn/selling-partner-api-models/tree/main/clients/sellingpartner-api-aa-csharp AWSSigV4Signer .

dannyworkingft commented 3 years ago

For those who want to copy and paste and see it work successfully, I have made changes needed to work correctly as of April 9, 2021 (renamed the variables to be more clear what client id/secret are required and added comments to show what some of them should start with). Be sure to add nuget package of AWSSDK.SecurityToken (and maybe RestSharp).

using Amazon;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using Amazon.SellingPartnerAPIAA;
using RestSharp;
using System;
using System.Threading;

namespace amazon_test_code
{
    class Program
    {
        static string MARKETPLACE_ID = "ATVPDKIKX0DER"; // for US.  See https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/developer-guide/SellingPartnerApiDeveloperGuide.md#marketplaceid-values for other countries.

        static void Main(string[] args)
        {
            var resource = $"/orders/v0/orders";
            IRestRequest restRequest = new RestRequest(resource, Method.GET);
            restRequest.AddParameter("MarketplaceIds", MARKETPLACE_ID, ParameterType.QueryString);
            restRequest.AddParameter("CreatedAfter", DateTime.UtcNow.AddDays(-5).ToString("yyyy-MM-dd"), ParameterType.QueryString);
            restRequest.AddParameter("CreatedBefore", DateTime.UtcNow.ToString("yyyy-MM-dd"), ParameterType.QueryString);

            var client = new RestClient("https://sellingpartnerapi-na.amazon.com");

            var credentials = new SellerAPICredentials();
            restRequest = SignWithAccessToken(restRequest, credentials.LWA_App_ClientId, credentials.LWA_App_ClientSecret, credentials.RefreshToken);

            restRequest = SignWithSTSKeysAndSecurityTokenn(restRequest, client.BaseUrl.Host, credentials.RoleARN, credentials.AWSKey, credentials.AWSSecret);

            var response = client.Execute(restRequest);

            Console.WriteLine("");
        }

        private static IRestRequest SignWithAccessToken(IRestRequest restRequest, string clientId, string clientSecret, string refreshToken)
        {
            var lwaAuthorizationCredentials = new LWAAuthorizationCredentials
            {
                ClientId = clientId,
                ClientSecret = clientSecret,
                Endpoint = new Uri("https://api.amazon.com/auth/o2/token"),
                RefreshToken = refreshToken,
            };

            return new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restRequest);
        }

        private static IRestRequest SignWithSTSKeysAndSecurityTokenn(IRestRequest restRequest, string host, string roleARN, string accessKey, string secretKey)
        {
            AssumeRoleResponse response1 = null;
            using (var STSClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey, RegionEndpoint.USEast1))
            {
                var req = new AssumeRoleRequest()
                {
                    RoleArn = roleARN,
                    DurationSeconds = 950, //put anything you want here
                    RoleSessionName = Guid.NewGuid().ToString()
                };

                response1 = STSClient.AssumeRoleAsync(req, new CancellationToken()).Result;
            }

            //auth step 3
            var awsAuthenticationCredentials = new AWSAuthenticationCredentials
            {
                AccessKeyId = response1.Credentials.AccessKeyId,
                SecretKey = response1.Credentials.SecretAccessKey,
                Region = "us-east-1"
            };

            restRequest.AddHeader("x-amz-security-token", response1.Credentials.SessionToken);

            return new AWSSigV4Signer(awsAuthenticationCredentials)
                            .Sign(restRequest, host);
        }
    }

    public class SellerAPICredentials
    {
        public string LWA_App_ClientId = xxxxxxxxxxxxxxx; //amzn...
        public string LWA_App_ClientSecret = xxxxxxxxxxxxxxx;
        public string RefreshToken = xxxxxxxxxxxxxxx; //Atzr...
        public string AWSKey = xxxxxxxxxxxxxxx;
        public string AWSSecret = xxxxxxxxxxxxxxx;
        public string RoleARN = xxxxxxxxxxxxxxx; //arn...
    }
}
nrogers805 commented 3 years ago

Hi

Not sure you have went through this process to create your application: https://github.com/amzn/selling-partner-api-docs/blob/main/guides/developer-guide/SellingPartnerApiDeveloperGuide.md

After your are done with above, then you can follow these steps for getting your orders:

Step 1: Make sure you self auth your app in seller central. and click Generate Token to get your refresh token.

Step 2: Make sure you download the credentials of the user (AWS key and secret) you created in above documentation

Step 3: Go ahead and download this: https://github.com/amzn/selling-partner-api-models/tree/main/clients/sellingpartner-api-aa-csharp

IMPORTANT NOTE: These are R&D examples/codes and code, and there is no guarantee that it will work for you or anybody else.. I am still in learning and wanted to share my experience

Step 4: Add new console app and then add Amazon.SellingPartnerAPIAA to console app

Step 5: Setup your request

var resource = $"/orders/v0/orders"; IRestRequest restRequest = new RestRequest(resource, Method.GET);

      restRequest.AddParameter("MarketplaceIds", MARKETPLACE_ID, ParameterType.QueryString);
      restRequest.AddParameter("CreatedAfter", DateTime.UtcNow.AddDays(-5).ToString("yyyy-MM-dd"), ParameterType.QueryString);

Step 6: The most important step, ppl (like me) spent days to figure out how to that... Create two functions to sign your app with your access token and your AWS keys

private static IRestRequest SignWithAccessToken(IRestRequest restRequest, string clientId, string clientSecret, string refreshToken) { var lwaAuthorizationCredentials = new LWAAuthorizationCredentials { ClientId = clientId, ClientSecret = clientSecret, Endpoint = new Uri("https://api.amazon.com/auth/o2/token"), RefreshToken = refreshToken, };

      return new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restRequest);
  }

and this is for your AWS keys

Note1: roleARN This is the role IRN you created with your app (refer the first document) Note2: The Amazon documents are missing (surprised, surprised) steps. This AssumeRole call is very important otherwise you will keep getting Forbidden

private static IRestRequest SignWithSTSKeysAndSecurityTokenn(IRestRequest restRequest, string host, string roleARN, string accessKey, string secretKey) { AssumeRoleResponse response1 = null; using (var STSClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey, RegionEndpoint.USEast1)) { var req = new AssumeRoleRequest() { RoleArn = roleARN, DurationSeconds = 950, //put anything you want here RoleSessionName = Guid.NewGuid().ToString() };

          response1 = STSClient.AssumeRoleAsync(req, new CancellationToken()).Result;
      }

      //auth step 3
      var awsAuthenticationCredentials = new AWSAuthenticationCredentials
      {
          AccessKeyId = response1.Credentials.AccessKeyId,
          SecretKey = response1.Credentials.SecretAccessKey,
          Region = "us-east-1"
      };

      restRequest.AddHeader("x-amz-security-token", response1.Credentials.SessionToken);

      return new AWSSigV4Signer(awsAuthenticationCredentials)
                      .Sign(restRequest, host);
  }

Now sign your request:

create some class like that and fill it wit your info

public class SellerAPICredentials { public string ClientId { get; set; } public string ClientSecret { get; set; } public string RefreshToken { get; set; } public string AWSKey { get; set; } public string AWSSecret { get; set; } public string RoleARN { get; set; } }

Then call these functions to sign your request

restRequest = SignWithAccessToken(restRequest, credentials.ClientId, credentials.ClientSecret, credentials.RefreshToken);

restRequest = SignWithSTSKeysAndSecurityTokenn(restRequest, Client.BaseUrl.Host, credentials.RoleARN, credentials.AWSKey, credentials.AWSSecret, overrideHost);

Step 5: Finally use your request to call

var client = new RestClient("https://sellingpartnerapi-na.amazon.com"); var response = client.Execute(restRequest);

Good luck!

Oguz

Why are all these links giving 404 Not Found ?

nafberger commented 3 years ago

hi I followed the amazon directions exactly, and I downloaded your latest code, its giving me an error like this One or more errors occurred. (User: arn:**:user/*.com is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam***:role/***ner-role). what am I doing wrong. please help

xbaha commented 3 years ago

@dannyatftecu hello, your code worked for me, but when I tried to get the date by a specific time it gave me a forbidden error, I tried DateTime.UtcNow.ToString("o"); also, DateTime.UtcNow.ToString("yyyy-MM-ddTHH\:mm\:ss.fffffffzzz");

have you tried that?

ytcitsupport-jlin commented 3 years ago

@tenitre Thank you for the answer and code. I wonder where can I found the refresh token? I couldn't find anything about it refresh token in the migration guide.

RafaelDN commented 3 years ago

For those who want to copy and paste and see it work successfully, I have made changes needed to work correctly as of April 9, 2021 (renamed the variables to be more clear what client id/secret are required and added comments to show what some of them should start with). Be sure to add nuget package of AWSSDK.SecurityToken (and maybe RestSharp).

using Amazon;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using Amazon.SellingPartnerAPIAA;
using RestSharp;
using System;
using System.Threading;

namespace amazon_test_code
{
    class Program
    {
        static string MARKETPLACE_ID = "ATVPDKIKX0DER"; // for US.  See https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/developer-guide/SellingPartnerApiDeveloperGuide.md#marketplaceid-values for other countries.

        static void Main(string[] args)
        {
            var resource = $"/orders/v0/orders";
            IRestRequest restRequest = new RestRequest(resource, Method.GET);
            restRequest.AddParameter("MarketplaceIds", MARKETPLACE_ID, ParameterType.QueryString);
            restRequest.AddParameter("CreatedAfter", DateTime.UtcNow.AddDays(-5).ToString("yyyy-MM-dd"), ParameterType.QueryString);
            restRequest.AddParameter("CreatedBefore", DateTime.UtcNow.ToString("yyyy-MM-dd"), ParameterType.QueryString);

            var client = new RestClient("https://sellingpartnerapi-na.amazon.com");

            var credentials = new SellerAPICredentials();
            restRequest = SignWithAccessToken(restRequest, credentials.LWA_App_ClientId, credentials.LWA_App_ClientSecret, credentials.RefreshToken);

            restRequest = SignWithSTSKeysAndSecurityTokenn(restRequest, client.BaseUrl.Host, credentials.RoleARN, credentials.AWSKey, credentials.AWSSecret);

            var response = client.Execute(restRequest);

            Console.WriteLine("");
        }

        private static IRestRequest SignWithAccessToken(IRestRequest restRequest, string clientId, string clientSecret, string refreshToken)
        {
            var lwaAuthorizationCredentials = new LWAAuthorizationCredentials
            {
                ClientId = clientId,
                ClientSecret = clientSecret,
                Endpoint = new Uri("https://api.amazon.com/auth/o2/token"),
                RefreshToken = refreshToken,
            };

            return new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restRequest);
        }

        private static IRestRequest SignWithSTSKeysAndSecurityTokenn(IRestRequest restRequest, string host, string roleARN, string accessKey, string secretKey)
        {
            AssumeRoleResponse response1 = null;
            using (var STSClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey, RegionEndpoint.USEast1))
            {
                var req = new AssumeRoleRequest()
                {
                    RoleArn = roleARN,
                    DurationSeconds = 950, //put anything you want here
                    RoleSessionName = Guid.NewGuid().ToString()
                };

                response1 = STSClient.AssumeRoleAsync(req, new CancellationToken()).Result;
            }

            //auth step 3
            var awsAuthenticationCredentials = new AWSAuthenticationCredentials
            {
                AccessKeyId = response1.Credentials.AccessKeyId,
                SecretKey = response1.Credentials.SecretAccessKey,
                Region = "us-east-1"
            };

            restRequest.AddHeader("x-amz-security-token", response1.Credentials.SessionToken);

            return new AWSSigV4Signer(awsAuthenticationCredentials)
                            .Sign(restRequest, host);
        }
    }

    public class SellerAPICredentials
    {
        public string LWA_App_ClientId = xxxxxxxxxxxxxxx; //amzn...
        public string LWA_App_ClientSecret = xxxxxxxxxxxxxxx;
        public string RefreshToken = xxxxxxxxxxxxxxx; //Atzr...
        public string AWSKey = xxxxxxxxxxxxxxx;
        public string AWSSecret = xxxxxxxxxxxxxxx;
        public string RoleARN = xxxxxxxxxxxxxxx; //arn...
    }
}

Yep, this worket for me.

I was missing the SignWithSTSKeysAndSecurityTokenn (I didn't found nothning about it in the docs).

Thank you very much!

mctozal commented 3 years ago

Hi

Not sure you have went through this process to create your application: https://github.com/amzn/selling-partner-api-docs/blob/main/guides/developer-guide/SellingPartnerApiDeveloperGuide.md

After your are done with above, then you can follow these steps for getting your orders:

Step 1: Make sure you self auth your app in seller central. and click Generate Token to get your refresh token.

Step 2: Make sure you download the credentials of the user (AWS key and secret) you created in above documentation

Step 3: Go ahead and download this: https://github.com/amzn/selling-partner-api-models/tree/main/clients/sellingpartner-api-aa-csharp

IMPORTANT NOTE: These are R&D examples/codes and code, and there is no guarantee that it will work for you or anybody else.. I am still in learning and wanted to share my experience

Step 4: Add new console app and then add Amazon.SellingPartnerAPIAA to console app

Step 5: Setup your request

var resource = $"/orders/v0/orders"; IRestRequest restRequest = new RestRequest(resource, Method.GET);

      restRequest.AddParameter("MarketplaceIds", MARKETPLACE_ID, ParameterType.QueryString);
      restRequest.AddParameter("CreatedAfter", DateTime.UtcNow.AddDays(-5).ToString("yyyy-MM-dd"), ParameterType.QueryString);

Step 6: The most important step, ppl (like me) spent days to figure out how to that... Create two functions to sign your app with your access token and your AWS keys

private static IRestRequest SignWithAccessToken(IRestRequest restRequest, string clientId, string clientSecret, string refreshToken) { var lwaAuthorizationCredentials = new LWAAuthorizationCredentials { ClientId = clientId, ClientSecret = clientSecret, Endpoint = new Uri("https://api.amazon.com/auth/o2/token"), RefreshToken = refreshToken, };

      return new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restRequest);
  }

and this is for your AWS keys

Note1: roleARN This is the role IRN you created with your app (refer the first document) Note2: The Amazon documents are missing (surprised, surprised) steps. This AssumeRole call is very important otherwise you will keep getting Forbidden

private static IRestRequest SignWithSTSKeysAndSecurityTokenn(IRestRequest restRequest, string host, string roleARN, string accessKey, string secretKey) { AssumeRoleResponse response1 = null; using (var STSClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey, RegionEndpoint.USEast1)) { var req = new AssumeRoleRequest() { RoleArn = roleARN, DurationSeconds = 950, //put anything you want here RoleSessionName = Guid.NewGuid().ToString() };

          response1 = STSClient.AssumeRoleAsync(req, new CancellationToken()).Result;
      }

      //auth step 3
      var awsAuthenticationCredentials = new AWSAuthenticationCredentials
      {
          AccessKeyId = response1.Credentials.AccessKeyId,
          SecretKey = response1.Credentials.SecretAccessKey,
          Region = "us-east-1"
      };

      restRequest.AddHeader("x-amz-security-token", response1.Credentials.SessionToken);

      return new AWSSigV4Signer(awsAuthenticationCredentials)
                      .Sign(restRequest, host);
  }

Now sign your request:

create some class like that and fill it wit your info

public class SellerAPICredentials { public string ClientId { get; set; } public string ClientSecret { get; set; } public string RefreshToken { get; set; } public string AWSKey { get; set; } public string AWSSecret { get; set; } public string RoleARN { get; set; } }

Then call these functions to sign your request

restRequest = SignWithAccessToken(restRequest, credentials.ClientId, credentials.ClientSecret, credentials.RefreshToken);

restRequest = SignWithSTSKeysAndSecurityTokenn(restRequest, Client.BaseUrl.Host, credentials.RoleARN, credentials.AWSKey, credentials.AWSSecret, overrideHost);

Step 5: Finally use your request to call

var client = new RestClient("https://sellingpartnerapi-na.amazon.com"); var response = client.Execute(restRequest);

Good luck!

Oguz

thank you it solved my problem i got rid of wasting time

kevnhowe commented 3 years ago

Has anyone successfully built a working SDK from the swagger templates? I was finally able to get past the myriad of build errors and get CSC to compile all modules, apis and the client into a single dll using the instructions. However, there is absolutely no documentation on using the SDK in a project. If anyone has a working example of a simple call using credentials with the client SDK I'd appreciate a peek. :)

nafberger commented 3 years ago

hi everyone here, thank g-d we have a c# example on how to make calls to amazon. thanks @tenitre, it was a huge help, now we need to code modified in order to use it when calling the authorization API and when getting new clients authenticated, is anyone ready to help us, we are willing to pay, and the code will remain posted here

jamesaq12wsx commented 3 years ago

Hi everyone, I made a package for Amazon SP-API request, here is the NuGet's link, currently it help you sign the request, refresh Amazon complicate authorization flow. Currently I implement order and feed API, If you are interested building this package with me please contact me.

kevnhowe commented 3 years ago

Has anyone successfully built a working SDK from the swagger templates? I was finally able to get past the myriad of build errors and get CSC to compile all modules, apis and the client into a single dll using the instructions. However, there is absolutely no documentation on using the SDK in a project. If anyone has a working example of a simple call using credentials with the client SDK I'd appreciate a peek. :)

I was able to roll the solution documented by @tenitre into the SellingPartnerAPIAA so that the compiled library can be used to handle the STS token header with the compiled C# SDK without having to make code changes to the SPAPI SDK. I've added a SessionToken property, and a GetSTSAuthenticationCredentials() method, which returns the Credentials and session token from the AssumeRole Response to the APIAA.AWSAuthenticationCredentials class.

In my app, I've passed my IAM user credentials and RoleARN to the new method in order to get the fully compatible AWSAuthenticationCredentials back, including the SessionToken. The session token then gets passed to the API Call using the SDK's Configuration.AddDefaultHeader() method.

I would rather not have to modify Amazon's source code to get this to work, but I've taken the lightest touch approach I could think of. Hopefully, they will make similar changes to the APIAA code in order to account for the AssumeRole requirements.

What this means for me is that I can now use all of the SDK modules and SPAPI Client out of the box, without having to implement my own API Call solution for calling each and every sp-api.

If anyone is interested, I will post my modifications here. just let me know.

nafberger commented 3 years ago

@jamesaq12wsx I started using your stuff, it looks great, does it have a call to call the GetAuthorizationCode call, I cant find it.

mctozal commented 3 years ago

did anyone succeed product feed with c# ? could anyone show the way? =)

On Sun, Aug 1, 2021 at 11:44 PM nafberger @.***> wrote:

@jamesaq12wsx https://github.com/jamesaq12wsx I started using your stuff, it looks great, does it have a call to call the GetAuthorizationCode call, I cant fine it.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/amzn/selling-partner-api-models/issues/31#issuecomment-890583851, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKV4JUK4F5PZTMB4H3QUUGTT2WWZ5ANCNFSM4T5EFVWQ .

jamesaq12wsx commented 3 years ago

@nafberger Thanks for your feedback. I haven't add GetAuthorizationCode, I'll update asap. By the way, according from amazon, to let GetAuthrizationCode call works (prod or sandbox) need your application been published with SP-API or Hybrid mode.

nafberger commented 3 years ago

Huge thanks @jamesaq12wsx. yes our app is hybrid now. waiting for your change

mctozal commented 3 years ago

I observed your package it needs lots of help! interfaces are dropped its only useful for authorize. Keep it going it seems lot of people gonna use it

On Thu, Jul 29, 2021 at 8:49 PM James Lin @.***> wrote:

Hi everyone, I made a package for Amazon SP-API request, here is the NuGet's link https://www.nuget.org/packages/AmzSpApi/, currently it help you sign the request, refresh Amazon complicate authorization flow. Currently I implement order and feed API, If you are interested building this package with me please contact me.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/amzn/selling-partner-api-models/issues/31#issuecomment-889340963, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKV4JUISSTBGZGDYP22VOT3T2GIBLANCNFSM4T5EFVWQ .

sanjayacs commented 3 years ago

@tenitre The entire AWS user access, role, user ARN, STS stuff is wild for someone who has never done it. So many moving parts. I am pretty sure I did it correctly and our application is authorized by Amazon for our vendor central account but I am still getting a forbidden error. For what it is worth below is the code in it's entirety.

I appreciate you responding and giving some help. I presume my issue at this point has to do with IAM or the application authorization process and I would need Amazon customer service to respond to a ticket some time in the next year to move forward. If you notice any issues below let me know. If I figure anything out I will post it here as well so everyone can see.

using Amazon;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using Amazon.SellingPartnerAPIAA;
using RestSharp;
using System;
using System.Threading;

namespace amazon_df_scratchpad
{
    class Program
    {
        static void Main(string[] args)
        {
            var resource = $"/vendor/directFulfillment/orders/v1/purchaseOrders";
            IRestRequest restRequest = new RestRequest(resource, Method.GET);

            restRequest.AddParameter("createdAfter", DateTime.UtcNow.AddDays(-5).ToString("yyyy-MM-dd"), ParameterType.QueryString);
            restRequest.AddParameter("createdBefore", DateTime.UtcNow.ToString("yyyy-MM-dd"), ParameterType.QueryString);

            var client = new RestClient("https://sellingpartnerapi-na.amazon.com");

            var credentials = new SellerAPICredentials();
            restRequest = SignWithAccessToken(restRequest, credentials.ClientId, credentials.ClientSecret, credentials.RefreshToken);

            restRequest = SignWithSTSKeysAndSecurityTokenn(restRequest, client.BaseUrl.Host, credentials.RoleARN, credentials.AWSKey, credentials.AWSSecret);

            var response = client.Execute(restRequest);

            Console.WriteLine("");
        }

        private static IRestRequest SignWithAccessToken(IRestRequest restRequest, string clientId, string clientSecret, string refreshToken)
        {
            var lwaAuthorizationCredentials = new LWAAuthorizationCredentials
            {
                ClientId = clientId,
                ClientSecret = clientSecret,
                Endpoint = new Uri("https://api.amazon.com/auth/o2/token"),
                RefreshToken = refreshToken,
            };

            return new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restRequest);
        }

        private static IRestRequest SignWithSTSKeysAndSecurityTokenn(IRestRequest restRequest, string host, string roleARN, string accessKey, string secretKey)
        {
            AssumeRoleResponse response1 = null;
            using (var STSClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey, RegionEndpoint.USEast1))
            {
                var req = new AssumeRoleRequest()
                {
                    RoleArn = roleARN,
                    DurationSeconds = 950, //put anything you want here
                    RoleSessionName = Guid.NewGuid().ToString()
                };

                response1 = STSClient.AssumeRoleAsync(req, new CancellationToken()).Result;
            }

            //auth step 3
            var awsAuthenticationCredentials = new AWSAuthenticationCredentials
            {
                AccessKeyId = response1.Credentials.AccessKeyId,
                SecretKey = response1.Credentials.SecretAccessKey,
                Region = "us-east-1"
            };

            restRequest.AddHeader("x-amz-security-token", response1.Credentials.SessionToken);

            return new AWSSigV4Signer(awsAuthenticationCredentials)
                            .Sign(restRequest, host);
        }
    }

    public class SellerAPICredentials
    {
        public string ClientId = xxxxxxxxxxxxxxxxxxx;
        public string ClientSecret = xxxxxxxxxxxxxxxxxxx;
        public string RefreshToken = xxxxxxxxxxxxxxxxxxx;
        public string AWSKey = xxxxxxxxxxxxxxxxxxx;
        public string AWSSecret = xxxxxxxxxxxxxxxxxxx;
        public string RoleARN = xxxxxxxxxxxxxxxxxxx;
    }
}
`

same code i have added into my application, i got the access token but when i call the order API i am getting the Access denied issue. please guild me what i am missing.

DawidWawrzyniak commented 3 years ago

You have an invalid date format. It should be in ISO-8601 date/time format.

quehvbg commented 3 years ago

I shared doc and guid, source code me have fined , it working 100% with .net

  1. Document Link https://www.cnblogs.com/Cxiaoao/p/14326709.html

  2. Git Source Link https://github.com/Cxiaoao/amazon-sellingpartner-api

Note : Your need change query param in source as example below request.AddQueryParameter("MarketplaceIds", "A2EUQ1WTGCTBG2"); To request.AddParameter("MarketplaceIds", "ATVPDKIKX0DER", ParameterType.QueryString); request.AddParameter("CreatedAfter", DateTime.UtcNow.AddDays(-50).ToString("yyyy-MM-dd"), ParameterType.QueryString);

mctozal commented 3 years ago

God bless your hands but just a little problem it only getting orders its %10 of whole sp-api.

5 Ağu 2021 Per 11:43 tarihinde Sankine Software Inc < @.***> şunu yazdı:

I shared doc and guid, source code me have fined , it working 100% with .net

1.

Document Link https://www.cnblogs.com/Cxiaoao/p/14326709.html 2.

Git Source Link https://github.com/Cxiaoao/amazon-sellingpartner-api

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/amzn/selling-partner-api-models/issues/31#issuecomment-893279254, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKV4JUK4AZS276CFGN33IIDT3JFKHANCNFSM4T5EFVWQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

quehvbg commented 3 years ago

God bless your hands but just a little problem it only getting orders its %10 of whole sp-api. 5 Ağu 2021 Per 11:43 tarihinde Sankine Software Inc < @.***> şunu yazdı: I shared doc and guid, source code me have fined , it working 100% with .net 1. Document Link https://www.cnblogs.com/Cxiaoao/p/14326709.html 2. Git Source Link https://github.com/Cxiaoao/amazon-sellingpartner-api — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#31 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKV4JUK4AZS276CFGN33IIDT3JFKHANCNFSM4T5EFVWQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

You need call with another region and market place to get all order on Seller Center

Almazzzzzz891 commented 3 years ago

Hello guys, anyone know where I can find refresh token?

mctozal commented 3 years ago

go to sellercentral => develop apps => authorize and you can generate a refresh token.

On Tue, Sep 7, 2021 at 6:37 AM Almazzzzzz891 @.***> wrote:

Hello guys, anyone know where I can find refresh token?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/amzn/selling-partner-api-models/issues/31#issuecomment-913965500, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKV4JUOBLII6CP4XUCYLTK3UAWCF3ANCNFSM4T5EFVWQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

Almazzzzzz891 commented 3 years ago

go to sellercentral => develop apps => authorize and you can generate a refresh token. On Tue, Sep 7, 2021 at 6:37 AM Almazzzzzz891 @.***> wrote: Hello guys, anyone know where I can find refresh token? — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#31 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKV4JUOBLII6CP4XUCYLTK3UAWCF3ANCNFSM4T5EFVWQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

thx

kadirresitkaya commented 2 years ago

Hi,

I am an Amazon MWS developer and will be migrating from MWS to SP-API. I want you to help me add new products. I couldn't find any sources in the new product feed. I have the product.xsd file but I can't figure out how to make an XML file with it. Can you help me on this issue? For example, I don't know how to select the category, how to enter the product properties for the category, etc. Thanks in advance for the help.

FelixFuentes777 commented 2 years ago

Hi, I am trying to get the SP-API process working. Where is the method AmazonSecurityTokenServiceClient located from the examples above ? Any help is appreciated.

michibr81 commented 2 years ago

It's also possible to use MFA/OTP when assuming role:

 var req = new AssumeRoleRequest()
                {
                    RoleArn = roleARN,
                    DurationSeconds = 950, //put anything you want here
                    RoleSessionName = Guid.NewGuid().ToString()
                    SerialNumber = userArn,
                    TokenCode = OneTimeOTPKey
                };
coder771 commented 2 years ago

I shared doc and guid, source code me have fined , it working 100% with .net

  1. Document Link https://www.cnblogs.com/Cxiaoao/p/14326709.html
  2. Git Source Link https://github.com/Cxiaoao/amazon-sellingpartner-api

Note : Your need change query param in source as example below request.AddQueryParameter("MarketplaceIds", "A2EUQ1WTGCTBG2"); To request.AddParameter("MarketplaceIds", "ATVPDKIKX0DER", ParameterType.QueryString); request.AddParameter("CreatedAfter", DateTime.UtcNow.AddDays(-50).ToString("yyyy-MM-dd"), ParameterType.QueryString);

@quehvbg your sample to do with invoke using rolearn doesnt work for me, think its to do with the setup I have in AWS and STS, I'm unable to follow the screenshot in documentation as it not being in english Sorry.

I have registered my app in seller central with IAM User Have you attached STS policy to user or Role in the screenshot? I have it attached to the user as below. is that correct?

image

jadanah commented 2 years ago

Here's a link to my repo which has all the amazon selling partner api client's with some usage samples built via nswag using httpclient vs. amazon's restsharp implementation.

https://github.com/jadanah/amazon-selling-partner-api-csharp-samples

hinavinayak commented 1 year ago

Closing as resolution by dev community.