diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..52e8b63d Binary files /dev/null and b/.DS_Store differ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..a4d74a71 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,98 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '45 7 * * 3' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: csharp + build-mode: none + - language: java-kotlin + build-mode: none # This mode only analyzes Java. Set this to 'autobuild' or 'manual' to analyze Kotlin too. + - language: javascript-typescript + build-mode: none + - language: python + build-mode: none + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/gradle-publish.yml b/.github/workflows/gradle-publish.yml new file mode 100644 index 00000000..20d17dc3 --- /dev/null +++ b/.github/workflows/gradle-publish.yml @@ -0,0 +1,44 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created +# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle + +name: Gradle Package + +on: + release: + types: [created] + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 + + - name: Build with Gradle + run: ./gradlew build + + # The USERNAME and TOKEN need to correspond to the credentials environment variables used in + # the publishing section of your build.gradle + - name: Publish to GitHub Packages + run: ./gradlew publish + env: + USERNAME: ${{ github.actor }} + TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml new file mode 100644 index 00000000..f2c9e97c --- /dev/null +++ b/.github/workflows/static.yml @@ -0,0 +1,43 @@ +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: '.' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 00000000..f48cf130 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,8 @@ + + + { + "keyToString": { + "settings.editor.selected.configurable": "aws" + } +} + \ No newline at end of file diff --git a/clients/sellingpartner-api-aa-csharp/Config b/clients/sellingpartner-api-aa-csharp/Config new file mode 100644 index 00000000..e70e978f --- /dev/null +++ b/clients/sellingpartner-api-aa-csharp/Config @@ -0,0 +1,26 @@ +package.SellingPartnerAPIAuthAndAuthCSharp = { + interfaces = (1.0); + + # Use NoOpBuild. See https://w.amazon.com/index.php/BrazilBuildSystem/NoOpBuild + build-system = no-op; + build-tools = { + 1.0 = { + NoOpBuild = 1.0; + }; + }; + + # Use runtime-dependencies for when you want to bring in additional + # packages when deploying. + # Use dependencies instead if you intend for these dependencies to + # be exported to other packages that build against you. + dependencies = { + 1.0 = { + }; + }; + + runtime-dependencies = { + 1.0 = { + }; + }; + +}; diff --git a/clients/sellingpartner-api-aa-csharp/README.md b/clients/sellingpartner-api-aa-csharp/README.md index be5d7712..2e156f50 100644 --- a/clients/sellingpartner-api-aa-csharp/README.md +++ b/clients/sellingpartner-api-aa-csharp/README.md @@ -38,35 +38,38 @@ restRequest = new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restR ``` Note the IRestRequest reference is treated as **mutable** when signed. -## RateLimitConfiguration -Interface to set and get rateLimit configurations that are used with RateLimiter. RateLimiter is used on client side to restrict the rate at which requests are made. RateLimiter Configuration takes Permit, rate which requests are made and TimeOut +## AWSSigV4Signer +Signs a request with [AWS Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) +using the provided AWS developer account credentials. + +This implementation of the IAM Role-based Authentication, will work only as long as the initial STS Token is valid (typically for 3600 seconds) and until an instance is able to refresh the STS Token on its own, otherwise, the Token needs to be reinitialized via the AWSSigV4Signer. *Example* ``` -RateLimitConfiguration rateLimitConfig = new RateLimitConfigurationOnRequests - { - RateLimitPermit = .., - WaitTimeOutInMilliSeconds = ... - }; +using RestSharp; +using Amazon.SellingPartnerAPIAA; -``` +string resource = "/my/api/path"; +RestClient restClient = new RestClient("https://..."); +IRestRequest restRequest = new RestRequest(resource, Method.GET); -## Exception -This package returns a custom LWAException when there is an error returned during LWA authorization. LWAException provides additional details like errorCode and errorDescription to help fix the issue. - -*Example* -``` -catch (LWAException e) - { - Console.WriteLine("LWA Exception when calling Selling partner API"); - Console.WriteLine(e.getErrorCode()); - Console.WriteLine(e.getErrorMessage()); - Console.WriteLine(e.Message); - } -``` +AWSAuthenticationCredentials awsAuthenticationCredentials = new AWSAuthenticationCredentials +{ + AccessKeyId = "..." + SecretKey = "..." + Region = "..." +}; -## Version -Selling Partner API Authentication/Authorization Library version 2.0. +AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider = new AWSAuthenticationCredentialsProvider +{ + RoleArn = "...", + RoleSessionName = "..." +}; + +restRequest = new AWSSigV4Signer(awsAuthenticationCredentials, awsAuthenticationCredentialsProvider) + .Sign(restRequest, restClient.BaseUrl.Host); +``` +Note the IRestRequest reference is treated as **mutable** when signed. ## Resources This package features Mustache templates designed for use with [swagger codegen](https://swagger.io/tools/swagger-codegen/). @@ -77,9 +80,11 @@ This package is built as a .NET Standard Library via a Visual Studio Solution wi ## Dependencies All dependencies can be installed via NuGet -- RestSharp - 106.12.0 +- RestSharp - 105.1.0 - Newtonsoft.Json 12.0.3 - NETStandard.Library 2.0.3 (platform-specific implementation requirements are documented on the [Microsoft .NET Guide](https://docs.microsoft.com/en-us/dotnet/standard/net-standard)) +- AWSSDK.Core 3.5.1.23 +- AWSSDK.SecurityToken 3.5.1.5 ## License Swagger Codegen templates are subject to the [Swagger Codegen License](https://github.com/swagger-api/swagger-codegen#license). diff --git a/clients/sellingpartner-api-aa-csharp/SellingPartnerAPIAuthAndAuthCSharp.sln b/clients/sellingpartner-api-aa-csharp/SellingPartnerAPIAuthAndAuthCSharp.sln index 1eec521e..cb6582ed 100644 --- a/clients/sellingpartner-api-aa-csharp/SellingPartnerAPIAuthAndAuthCSharp.sln +++ b/clients/sellingpartner-api-aa-csharp/SellingPartnerAPIAuthAndAuthCSharp.sln @@ -20,7 +20,4 @@ Global {12B130EB-1087-4F88-BDFA-3088868C0A46}.Release|Any CPU.ActiveCfg = Release|Any CPU {12B130EB-1087-4F88-BDFA-3088868C0A46}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - version = 2.0 - EndGlobalSection EndGlobal diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSAuthenticationCredentialsProvider.cs b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSAuthenticationCredentialsProvider.cs new file mode 100644 index 00000000..bf93f6c9 --- /dev/null +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSAuthenticationCredentialsProvider.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Amazon.SellingPartnerAPIAA +{ + /** + * AWSAuthenticationCredentialsProvider + */ + public class AWSAuthenticationCredentialsProvider + { + /** + * AWS IAM Role ARN + */ + public String RoleArn { get; set; } + + /** + * AWS IAM Role Session Name + */ + public String RoleSessionName { get; set; } + } +} diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSigV4Signer.cs b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSigV4Signer.cs new file mode 100644 index 00000000..eab99089 --- /dev/null +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSigV4Signer.cs @@ -0,0 +1,138 @@ +using System; +using System.Text; +using RestSharp; +using Amazon.Runtime; +using Amazon.SecurityToken; +using Amazon.SecurityToken.Model; +using System.Threading; + +namespace Amazon.SellingPartnerAPIAA +{ + public class AWSSigV4Signer + + { + public virtual AWSSignerHelper AwsSignerHelper { get; set; } + private AWSAuthenticationCredentials awsCredentials; + private AssumeRoleResponse assumeRole; + public const string SecurityTokenHeaderName = "X-Amz-Security-Token"; + + + /// + /// Constructor for AWSSigV4Signer + /// + /// AWS Developer Account Credentials + public AWSSigV4Signer(AWSAuthenticationCredentials awsAuthenticationCredentials) + { + awsCredentials = awsAuthenticationCredentials; + AwsSignerHelper = new AWSSignerHelper(); + } + + + /// + /// Overloaded Constructor for AWSSigV4Signer using IAM Role + /// + /// AWS Developer Account Credentials + /// AWS IAM Role and Session Name container + public AWSSigV4Signer(AWSAuthenticationCredentials awsAuthenticationCredentials, + AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider) + { + awsCredentials = awsAuthenticationCredentials; + BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials( + awsAuthenticationCredentials.AccessKeyId, awsAuthenticationCredentials.SecretKey); + AmazonSecurityTokenServiceClient sts = new AmazonSecurityTokenServiceClient(basicAWSCredentials); + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + assumeRole = sts.AssumeRoleAsync(new AssumeRoleRequest{ + RoleArn = awsAuthenticationCredentialsProvider.RoleArn, + RoleSessionName = awsAuthenticationCredentialsProvider.RoleSessionName + }).Result; + + AwsSignerHelper = new AWSSignerHelper(); + } + + /// + /// Signs a Request with AWS Signature Version 4 + /// + /// RestRequest which needs to be signed + /// Request endpoint + /// RestRequest with AWS Signature + public IRestRequest Sign(IRestRequest request, string host) + { + DateTime signingDate = AwsSignerHelper.SetDateAndHostHeaders(request, host); + + string signedHeaders = AwsSignerHelper.ExtractSignedHeaders(request); + + string hashedCanonicalRequest = CreateCanonicalRequest(request, signedHeaders); + + string stringToSign = AwsSignerHelper.BuildStringToSign(signingDate, + hashedCanonicalRequest, + awsCredentials.Region); + + if (assumeRole != null) + { + + Credentials credentials = assumeRole.Credentials; + AwsSignerHelper.SetSessionTokenHeader(request, credentials.SessionToken); + + string signature = AwsSignerHelper.CalculateSignature(stringToSign, + signingDate, + credentials.SecretAccessKey, + awsCredentials.Region); + AwsSignerHelper.AddSignature(request, + credentials.AccessKeyId, + signedHeaders, + signature, + awsCredentials.Region, + signingDate); + + return request; + } + else + { + + + + string signature = AwsSignerHelper.CalculateSignature(stringToSign, + signingDate, + awsCredentials.SecretKey, + awsCredentials.Region); + + AwsSignerHelper.AddSignature(request, + awsCredentials.AccessKeyId, + signedHeaders, + signature, + awsCredentials.Region, + signingDate); + + return request; + } + } + + private string CreateCanonicalRequest(IRestRequest restRequest, string signedHeaders) + { + var canonicalizedRequest = new StringBuilder(); + //Request Method + canonicalizedRequest.AppendFormat("{0}\n", restRequest.Method); + + //CanonicalURI + canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalURIParameters(restRequest.Resource)); + + //CanonicalQueryString + canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalQueryString(restRequest)); + + //CanonicalHeaders + canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalHeaders(restRequest)); + + //SignedHeaders + canonicalizedRequest.AppendFormat("{0}\n", signedHeaders); + + // Hash(digest) the payload in the body + canonicalizedRequest.AppendFormat(AwsSignerHelper.HashRequestBody(restRequest)); + + string canonicalRequest = canonicalizedRequest.ToString(); + + //Create a digest(hash) of the canonical request + return Utils.ToHex(Utils.Hash(canonicalRequest)); + } + } +} \ No newline at end of file diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSignerHelper.cs b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSignerHelper.cs new file mode 100644 index 00000000..c4ff9858 --- /dev/null +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSignerHelper.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using RestSharp; +using System.Text.RegularExpressions; +using System.Globalization; +using Amazon.SecurityToken.Model; + +namespace Amazon.SellingPartnerAPIAA +{ + public class AWSSignerHelper + { + public const string ISO8601BasicDateTimeFormat = "yyyyMMddTHHmmssZ"; + public const string ISO8601BasicDateFormat = "yyyyMMdd"; + + public const string XAmzDateHeaderName = "X-Amz-Date"; + public const string AuthorizationHeaderName = "Authorization"; + public const string CredentialSubHeaderName = "Credential"; + public const string SignatureSubHeaderName = "Signature"; + public const string SignedHeadersSubHeaderName = "SignedHeaders"; + public const string HostHeaderName = "host"; + public const string SecurityTokenHeaderName = "X-Amz-Security-Token"; + + public const string Scheme = "AWS4"; + public const string Algorithm = "HMAC-SHA256"; + public const string TerminationString = "aws4_request"; + public const string ServiceName = "execute-api"; + public const string Slash = "/"; + + private readonly static Regex CompressWhitespaceRegex = new Regex("\\s+"); + + public virtual IDateHelper DateHelper { get; set; } + + public AWSSignerHelper() + { + DateHelper = new SigningDateHelper(); + } + + /// + /// Returns URI encoded version of absolute path + /// + /// Resource path(absolute path) from the request + /// URI encoded version of absolute path + public virtual string ExtractCanonicalURIParameters(string resource) + { + string canonicalUri = string.Empty; + + if (string.IsNullOrEmpty(resource)) + { + canonicalUri = Slash; + } + else + { + if (!resource.StartsWith(Slash)) + { + canonicalUri = Slash; + } + //Split path at / into segments + IEnumerable encodedSegments = resource.Split(new char[] { '/' }, StringSplitOptions.None); + + // Encode twice + encodedSegments = encodedSegments.Select(segment => Utils.UrlEncode(segment)); + encodedSegments = encodedSegments.Select(segment => Utils.UrlEncode(segment)); + + canonicalUri += string.Join(Slash, encodedSegments.ToArray()); + } + + return canonicalUri; + } + + /// + /// Returns query parameters in canonical order with URL encoding + /// + /// RestRequest + /// Query parameters in canonical order with URL encoding + public virtual string ExtractCanonicalQueryString(IRestRequest request) + { + IDictionary queryParameters = request.Parameters + .Where(parameter => ParameterType.QueryString.Equals(parameter.Type)) + .ToDictionary(header => header.Name.Trim().ToString(), header => header.Value.ToString()); + + SortedDictionary sortedqueryParameters = new SortedDictionary(queryParameters); + + StringBuilder canonicalQueryString = new StringBuilder(); + foreach (var key in sortedqueryParameters.Keys) + { + if (canonicalQueryString.Length > 0) + { + canonicalQueryString.Append("&"); + } + canonicalQueryString.AppendFormat("{0}={1}", + Utils.UrlEncode(key), + Utils.UrlEncode(sortedqueryParameters[key])); + } + + return canonicalQueryString.ToString(); + } + + /// + /// Returns Http headers in canonical order with all header names to lowercase + /// + /// RestRequest + /// Returns Http headers in canonical order + public virtual string ExtractCanonicalHeaders(IRestRequest request) + { + IDictionary headers = request.Parameters + .Where(parameter => ParameterType.HttpHeader.Equals(parameter.Type)) + .ToDictionary(header => header.Name.Trim().ToLowerInvariant(), header => header.Value.ToString()); + + SortedDictionary sortedHeaders = new SortedDictionary(headers); + + StringBuilder headerString = new StringBuilder(); + + foreach (string headerName in sortedHeaders.Keys) + { + headerString.AppendFormat("{0}:{1}\n", + headerName, + CompressWhitespaceRegex.Replace(sortedHeaders[headerName].Trim(), " ")); + } + + return headerString.ToString(); + } + + /// + /// Returns list(as string) of Http headers in canonical order + /// + /// RestRequest + /// List of Http headers in canonical order + public virtual string ExtractSignedHeaders(IRestRequest request) + { + List rawHeaders = request.Parameters.Where(parameter => ParameterType.HttpHeader.Equals(parameter.Type)) + .Select(header => header.Name.Trim().ToLowerInvariant()) + .ToList(); + rawHeaders.Sort(StringComparer.OrdinalIgnoreCase); + + return string.Join(";", rawHeaders); + } + + /// + /// Returns hexadecimal hashed value(using SHA256) of payload in the body of request + /// + /// RestRequest + /// Hexadecimal hashed value of payload in the body of request + public virtual string HashRequestBody(IRestRequest request) + { + Parameter body = request.Parameters.FirstOrDefault(parameter => ParameterType.RequestBody.Equals(parameter.Type)); + string value = body != null ? body.Value.ToString() : string.Empty; + return Utils.ToHex(Utils.Hash(value)); + } + + /// + /// Builds the string for signing using signing date, hashed canonical request and region + /// + /// Signing Date + /// Hashed Canonical Request + /// Region + /// String to be used for signing + public virtual string BuildStringToSign(DateTime signingDate, string hashedCanonicalRequest, string region) + { + string scope = BuildScope(signingDate, region); + string stringToSign = string.Format(CultureInfo.InvariantCulture, "{0}-{1}\n{2}\n{3}\n{4}", + Scheme, + Algorithm, + signingDate.ToString(ISO8601BasicDateTimeFormat, CultureInfo.InvariantCulture), + scope, + hashedCanonicalRequest); + + return stringToSign; + } + + /// + /// Sets AWS4 mandated 'x-amz-date' and 'host' headers, returning the date/time that will + /// be used throughout the signing process. + /// + /// RestRequest + /// Request endpoint + /// Date and time used for x-amz-date, in UTC + public virtual DateTime SetDateAndHostHeaders(IRestRequest restRequest, string host) + { + restRequest.Parameters.RemoveAll(parameter => ParameterType.HttpHeader.Equals(parameter.Type) + && parameter.Name == XAmzDateHeaderName); + restRequest.Parameters.RemoveAll(parameter => ParameterType.HttpHeader.Equals(parameter.Type) + && parameter.Name == HostHeaderName); + + DateTime signingDate = DateHelper.GetUtcNow(); + + restRequest.AddHeader(XAmzDateHeaderName, signingDate.ToString(ISO8601BasicDateTimeFormat, CultureInfo.InvariantCulture)); + restRequest.AddHeader(HostHeaderName, host); + + return signingDate; + } + + /// + /// Sets AWS4 'X-Amz-Security-Token' header, used to pass the STS Token to + /// be used throughout the signing process. + /// + /// RestRequest + /// STS Session Token + public void SetSessionTokenHeader(IRestRequest restRequest, String sessionToken) + { + restRequest.Parameters.RemoveAll(parameter => ParameterType.HttpHeader.Equals(parameter.Type) + && parameter.Name == SecurityTokenHeaderName); + + restRequest.AddHeader(SecurityTokenHeaderName, sessionToken); + } + + /// + /// Calculates AWS4 signature for the string, prepared for signing + /// + /// String to be signed + /// Signing Date + /// Secret Key + /// Region + /// AWS4 Signature + public virtual string CalculateSignature(string stringToSign, + DateTime signingDate, + string secretKey, + string region) + { + string date = signingDate.ToString(ISO8601BasicDateFormat, CultureInfo.InvariantCulture); + byte[] kSecret = Encoding.UTF8.GetBytes(Scheme + secretKey); + byte[] kDate = Utils.GetKeyedHash(kSecret, date); + byte[] kRegion = Utils.GetKeyedHash(kDate, region); + byte[] kService = Utils.GetKeyedHash(kRegion, ServiceName); + byte[] kSigning = Utils.GetKeyedHash(kService, TerminationString); + + // Calculate the signature + return Utils.ToHex(Utils.GetKeyedHash(kSigning, stringToSign)); + } + + /// + /// Add a signature to a request in the form of an 'Authorization' header + /// + /// Request to be signed + /// Access Key Id + /// Signed Headers + /// The signature to add + /// AWS region for the request + /// Signature date + public virtual void AddSignature(IRestRequest restRequest, + string accessKeyId, + string signedHeaders, + string signature, + string region, + DateTime signingDate) + { + string scope = BuildScope(signingDate, region); + StringBuilder authorizationHeaderValueBuilder = new StringBuilder(); + authorizationHeaderValueBuilder.AppendFormat("{0}-{1}", Scheme, Algorithm); + authorizationHeaderValueBuilder.AppendFormat(" {0}={1}/{2},", CredentialSubHeaderName, accessKeyId, scope); + authorizationHeaderValueBuilder.AppendFormat(" {0}={1},", SignedHeadersSubHeaderName, signedHeaders); + authorizationHeaderValueBuilder.AppendFormat(" {0}={1}", SignatureSubHeaderName, signature); + + restRequest.AddHeader(AuthorizationHeaderName, authorizationHeaderValueBuilder.ToString()); + } + + private static string BuildScope(DateTime signingDate, string region) + { + return string.Format("{0}/{1}/{2}/{3}", + signingDate.ToString(ISO8601BasicDateFormat, CultureInfo.InvariantCulture), + region, + ServiceName, + TerminationString); + } + } +} diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/LWAAccessTokenRequestMeta.cs b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/LWAAccessTokenRequestMeta.cs index 1188272c..13da49f9 100644 --- a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/LWAAccessTokenRequestMeta.cs +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/LWAAccessTokenRequestMeta.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; namespace Amazon.SellingPartnerAPIAA diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/ApiClient.mustache b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/ApiClient.mustache index 52a4e56b..27e0e9b1 100644 --- a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/ApiClient.mustache +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/ApiClient.mustache @@ -22,8 +22,6 @@ using RestSharp.Portable.HttpClient; using RestSharp; {{/netStandard}} using Amazon.SellingPartnerAPIAA; -using RateLimiter; -using System.Threading; namespace {{packageName}}.Client { @@ -33,9 +31,8 @@ namespace {{packageName}}.Client {{>visibility}} partial class ApiClient { private LWAAuthorizationSigner lwaAuthorizationSigner; - private RateLimitConfiguration rateLimitConfig; - private TimeLimiter rateLimiter; - + private AWSSigV4Signer awsSigV4Signer; + private JsonSerializerSettings serializerSettings = new JsonSerializerSettings { ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor @@ -45,10 +42,10 @@ namespace {{packageName}}.Client /// Allows for extending request processing for generated code. /// /// The RestSharp request object - /// Thrown when there is an error during LWA Authorization private void InterceptRequest(IRestRequest request) { lwaAuthorizationSigner.Sign(request); + awsSigV4Signer.Sign(request, RestClient.BaseUrl.Host); } /// @@ -73,10 +70,13 @@ namespace {{packageName}}.Client {{/netStandard}} lwaAuthorizationSigner = new LWAAuthorizationSigner(Configuration.AuthorizationCredentials); - rateLimitConfig = Configuration.RateLimitConfig; - if(rateLimitConfig != null) - { - rateLimiter = TimeLimiter.GetFromMaxCountByInterval(rateLimitConfig.getRateLimitPermit(), TimeSpan.FromSeconds(1)); + if (Configuration.AuthenticationCredentialsProvider!=null) + { + awsSigV4Signer = new AWSSigV4Signer(configuration.AuthenticationCredentials, Configuration.AuthenticationCredentialsProvider); + } + else + { + awsSigV4Signer = new AWSSigV4Signer(Configuration.AuthenticationCredentials); } } @@ -141,7 +141,7 @@ namespace {{packageName}}.Client {{/netStandard}} {{^netStandard}} {{^supportsUWP}} - request.AddFile(param.Value.Name, param.Value.Writer, param.Value.FileName, param.Value.ContentLength, param.Value.ContentType); + request.AddFile(param.Value.Name, param.Value.Writer, param.Value.FileName, param.Value.ContentType); {{/supportsUWP}} {{#supportsUWP}} byte[] paramWriter = null; @@ -194,22 +194,6 @@ namespace {{packageName}}.Client RestClient.UserAgent = Configuration.UserAgent; InterceptRequest(request); - if(rateLimitConfig != null) - { - var cancellationSource = new CancellationTokenSource(rateLimitConfig.getTimeOut()); - try - { - var response = rateLimiter.Enqueue(() => RestClient.Execute(request), cancellationSource.Token); - InterceptResponse(request, response.Result); - return response.Result; - } - catch (AggregateException e) - { - throw new ApiException(429, "Throttled at client"); - } - } - else - { {{#netStandard}} var response = RestClient.Execute(request).Result; {{/netStandard}} @@ -225,7 +209,6 @@ namespace {{packageName}}.Client InterceptResponse(request, response); return (Object) response; - } } {{#supportsAsync}} /// @@ -251,19 +234,9 @@ namespace {{packageName}}.Client path, method, queryParams, postBody, headerParams, formParams, fileParams, pathParams, contentType); InterceptRequest(request); - if (rateLimitConfig != null) - { - var cancellationSource = new CancellationTokenSource(rateLimitConfig.getTimeOut()); - var response = await rateLimiter.Enqueue(() => RestClient.ExecuteTaskAsync(request), cancellationSource.Token); - InterceptResponse(request, response); - return response; - } - else - { - var response = await RestClient.Execute{{^netStandard}}TaskAsync{{/netStandard}}(request); - InterceptResponse(request, response); - return (Object)response; - } + var response = await RestClient.Execute{{^netStandard}}TaskAsync{{/netStandard}}(request); + InterceptResponse(request, response); + return (Object)response; }{{/supportsAsync}} /// @@ -608,4 +581,3 @@ namespace {{packageName}}.Client } } } - diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/Configuration.mustache b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/Configuration.mustache index 3038689d..8518e3b0 100644 --- a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/Configuration.mustache +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/Configuration.mustache @@ -275,6 +275,12 @@ namespace {{packageName}}.Client /// The RateLimitConfiguration public virtual RateLimitConfiguration RateLimitConfig { get; set; } + /// + /// Gets or sets the AWSAuthenticationCredentialsProvider for Amazon Selling Partner API Authentication + /// + /// The AWSAuthenticationCredentialsProvider + public virtual AWSAuthenticationCredentialsProvider AuthenticationCredentialsProvider { get; set; } + /// /// Gets the API key with prefix. /// diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/IReadableConfiguration.mustache b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/IReadableConfiguration.mustache index cae69555..a280b34c 100644 --- a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/IReadableConfiguration.mustache +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/IReadableConfiguration.mustache @@ -88,11 +88,17 @@ namespace {{packageName}}.Client /// /// AuthorizationCredentials LWAAuthorizationCredentials AuthorizationCredentials { get; } - + + /// + /// Gets the AWSAuthenticationCredentials for Amazon Selling Partner API Authentication + /// + /// AuthenticationCredentials + AWSAuthenticationCredentials AuthenticationCredentials { get; } + /// - /// Gets the RateLimitConfigurationOnRequests for Amazon Selling Partner API RateLimit + /// Gets the AWSAuthenticationCredentialsProvider for Amazon Selling Partner API Authentication /// - /// RateLimitConfiguration - RateLimitConfiguration RateLimitConfig { get; } + /// AWSAuthenticationCredentialsProvider + AWSAuthenticationCredentialsProvider AuthenticationCredentialsProvider { get; } } } diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/api.mustache b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/api.mustache index 17644f22..a9b1bcc3 100644 --- a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/api.mustache +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/resources/swagger-codegen/templates/api.mustache @@ -435,18 +435,17 @@ namespace {{packageName}}.{{apiPackage}} public class Builder { private LWAAuthorizationCredentials lwaAuthorizationCredentials; - private RateLimitConfiguration rateLimitConfiguration; + private AWSAuthenticationCredentials awsAuthenticationCredentials; public Builder SetLWAAuthorizationCredentials(LWAAuthorizationCredentials lwaAuthorizationCredentials) { this.lwaAuthorizationCredentials = lwaAuthorizationCredentials; return this; } - - - public Builder SetRateLimitConfiguration(RateLimitConfiguration rateLimitConfiguration) + + public Builder SetAWSAuthenticationCredentials(AWSAuthenticationCredentials awsAuthenticationCredentials) { - this.rateLimitConfiguration = rateLimitConfiguration; + this.awsAuthenticationCredentials = awsAuthenticationCredentials; return this; } @@ -457,11 +456,15 @@ namespace {{packageName}}.{{apiPackage}} throw new NullReferenceException("LWAAuthoriztionCredentials not set"); } + if (awsAuthenticationCredentials == null) + { + throw new NullReferenceException("AWSAuthenticationCredentials not set"); + } {{packageName}}.Client.Configuration configuration = new {{packageName}}.Client.Configuration() { AuthorizationCredentials = lwaAuthorizationCredentials, - RateLimitConfig = rateLimitConfiguration + AuthenticationCredentials = awsAuthenticationCredentials }; // default HTTP connection timeout (in milliseconds) diff --git a/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSigV4SignerTest.cs b/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSigV4SignerTest.cs new file mode 100644 index 00000000..c9b24807 --- /dev/null +++ b/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSigV4SignerTest.cs @@ -0,0 +1,88 @@ +using Moq; +using Xunit; +using RestSharp; +using Amazon.SellingPartnerAPIAA; +using System; + +namespace Amazon.SellingPartnerAPIAATests +{ + public class AWSSigV4SignerTest + { + private const string TestAccessKeyId = "aKey"; + private const string TestSecretKey = "sKey"; + private const string TestRegion = "us-east-1"; + private const string TestResourcePath = "iam/user"; + private const string TestHost = "sellingpartnerapi.amazon.com"; + + private RestRequest request; + private AWSSigV4Signer sigV4SignerUnderTest; + private Mock mockAWSSignerHelper; + + public AWSSigV4SignerTest() + { + request = new RestRequest(TestResourcePath, Method.GET); + + AWSAuthenticationCredentials authenticationCredentials = new AWSAuthenticationCredentials + { + AccessKeyId = TestAccessKeyId, + SecretKey = TestSecretKey, + Region = TestRegion + }; + mockAWSSignerHelper = new Mock(); + sigV4SignerUnderTest = new AWSSigV4Signer(authenticationCredentials); + sigV4SignerUnderTest.AwsSignerHelper = mockAWSSignerHelper.Object; + } + + [Fact] + public void TestSignRequest() + { + DateTime signingDate = DateTime.UtcNow; + string expectedHashedCanonicalRequest = "b7a5ea4c3179fcebed77f19ccd7d85795d4b7a1810709b55fa7ad3fd79ab6adc"; + string expectedSignedHeaders = "testSignedHeaders"; + string expectedSignature = "testSignature"; + string expectedStringToSign = "testStringToSign"; + mockAWSSignerHelper.Setup(signerHelper => signerHelper.SetDateAndHostHeaders(request, TestHost)) + .Returns(signingDate); + mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractCanonicalURIParameters(request.Resource)) + .Returns("testURIParameters"); + mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractCanonicalQueryString(request)) + .Returns("testCanonicalQueryString"); + mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractCanonicalHeaders(request)) + .Returns("testCanonicalHeaders"); + mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractSignedHeaders(request)) + .Returns(expectedSignedHeaders); + mockAWSSignerHelper.Setup(signerHelper => signerHelper.HashRequestBody(request)) + .Returns("testHashRequestBody"); + mockAWSSignerHelper.Setup(signerHelper => signerHelper.BuildStringToSign(signingDate, + expectedHashedCanonicalRequest, TestRegion)) + .Returns(expectedStringToSign); + mockAWSSignerHelper.Setup(signerHelper => signerHelper.CalculateSignature(expectedStringToSign, + signingDate, TestSecretKey, TestRegion)) + .Returns(expectedSignature); + + IRestRequest actualRestRequest = sigV4SignerUnderTest.Sign(request, TestHost); + + mockAWSSignerHelper.Verify(signerHelper => signerHelper.SetDateAndHostHeaders(request, TestHost)); + mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalURIParameters(request.Resource)); + mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalQueryString(request)); + mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalHeaders(request)); + mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractSignedHeaders(request)); + mockAWSSignerHelper.Verify(signerHelper => signerHelper.HashRequestBody(request)); + mockAWSSignerHelper.Verify(signerHelper => signerHelper.BuildStringToSign(signingDate, + expectedHashedCanonicalRequest, + TestRegion)); + mockAWSSignerHelper.Verify(signerHelper => signerHelper.CalculateSignature(expectedStringToSign, + signingDate, + TestSecretKey, + TestRegion)); + mockAWSSignerHelper.Verify(signerHelper => signerHelper.AddSignature(request, + TestAccessKeyId, + expectedSignedHeaders, + expectedSignature, + TestRegion, + signingDate)); + + Assert.Equal(request, actualRestRequest); + } + } +} diff --git a/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSignerHelperTest.cs b/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSignerHelperTest.cs new file mode 100644 index 00000000..2b6c5369 --- /dev/null +++ b/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSignerHelperTest.cs @@ -0,0 +1,288 @@ +using System; +using Xunit; +using RestSharp; +using Amazon.SellingPartnerAPIAA; +using System.Text; +using Moq; +using Amazon.SecurityToken.Model; +using Amazon.Runtime; +using Amazon.SecurityToken; + +namespace Amazon.SellingPartnerAPIAATests +{ + public class AWSSignerHelperTest + { + private const string Slash = "/"; + private const string ISOSigningDateTime = "20200504T121212Z"; + private const string ISOSigningDate = "20200504"; + private const string TestAccessKeyId = "aKey"; + private const string TestSecretKey = "sKey"; + private const string TestRegion = "us-east-1"; + private const string TestResourcePath = "iam/user"; + private const string TestHost = "sellingpartnerapi.amazon.com"; + private const string JsonMediaType = "application/json; charset=utf-8"; + private const string TestSessionToken = "sToken"; + + private static readonly DateTime SigningDate = DateTime.Parse("2020-05-04 12:12:12"); + + private AWSSignerHelper awsSignerHelperUnderTest; + + public AWSSignerHelperTest() + { + var mockDateHelper = new Mock(); + mockDateHelper.Setup(dateHelper => dateHelper.GetUtcNow()).Returns(SigningDate); + awsSignerHelperUnderTest = new AWSSignerHelper() { DateHelper = mockDateHelper.Object }; + } + + [Fact] + public void TestExtractCanonicalURIParameters() + { + IRestRequest request = new RestRequest(TestResourcePath, Method.GET); + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request.Resource); + Assert.Equal("/iam/user", result); + } + + [Fact] + public void TestExtractCanonicalURIParameters_ResourcePathWithSpace() + { + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters("iam/ user"); + Assert.Equal("/iam/%2520user", result); + } + + [Fact] + public void TestExtractCanonicalURIParameters_EmptyResourcePath() + { + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(string.Empty); + Assert.Equal(Slash, result); + } + + [Fact] + public void TestExtractCanonicalURIParameters_NullResourcePath() + { + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(null); + Assert.Equal(Slash, result); + } + + [Fact] + public void TestExtractCanonicalURIParameters_SlashPath() + { + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(Slash); + Assert.Equal(Slash, result); + } + + [Fact] + public void TestExtractCanonicalQueryString() + { + IRestRequest request = new RestRequest(); + request.AddQueryParameter("Version", "2010-05-08"); + request.AddQueryParameter("Action", "ListUsers"); + request.AddQueryParameter("RequestId", "1"); + + string result = awsSignerHelperUnderTest.ExtractCanonicalQueryString(request); + //Query parameters in canonical order + Assert.Equal("Action=ListUsers&RequestId=1&Version=2010-05-08", result); + } + + [Fact] + public void TestExtractCanonicalQueryString_EmptyQueryParameters() + { + string result = awsSignerHelperUnderTest.ExtractCanonicalQueryString(new RestRequest()); + Assert.Empty(result); + } + + [Fact] + public void TestExtractCanonicalQueryString_WithUrlEncoding() + { + IRestRequest request = new RestRequest(); + request.AddQueryParameter("Action^", "ListUsers$Roles"); + string result = awsSignerHelperUnderTest.ExtractCanonicalQueryString(request); + Assert.Equal("Action%5E=ListUsers%24Roles", result); + } + + [Fact] + public void TestExtractCanonicalHeaders() + { + IRestRequest request = new RestRequest(); + request.AddHeader("X-Amz-Date", "20150830T123600Z"); + request.AddHeader("Host", "iam.amazonaws.com"); + request.AddHeader("Content-Type", JsonMediaType); + + string result = awsSignerHelperUnderTest.ExtractCanonicalHeaders(request); + Assert.Equal("content-type:application/json; charset=utf-8\nhost:iam.amazonaws.com\n" + + "x-amz-date:20150830T123600Z\n", result); + } + + [Fact] + public void TestExtractCanonicalHeaders_NoHeader() + { + string result = awsSignerHelperUnderTest.ExtractCanonicalHeaders(new RestRequest()); + Assert.Empty(result); + } + + [Fact] + public void TestExtractSignedHeaders() + { + IRestRequest request = new RestRequest(); + request.AddHeader("X-Amz-Date", "20150830T123600Z"); + request.AddHeader("Host", "iam.amazonaws.com"); + request.AddHeader("Content-Type", JsonMediaType); + + string result = awsSignerHelperUnderTest.ExtractSignedHeaders(request); + Assert.Equal("content-type;host;x-amz-date", result); + } + + [Fact] + public void TestExtractSignedHeaders_NoHeader() + { + string result = awsSignerHelperUnderTest.ExtractSignedHeaders(new RestRequest()); + Assert.Empty(result); + } + + [Fact] + public void TestHashRequestBody() + { + IRestRequest request = new RestRequest(TestResourcePath, Method.POST); + request.AddJsonBody("{\"test\":\"payload\"}"); + + string result = awsSignerHelperUnderTest.HashRequestBody(request); + Assert.NotEmpty(result); + } + + [Fact] + public void TestHashRequestBody_NoBody() + { + string result = awsSignerHelperUnderTest.HashRequestBody(new RestRequest()); + Assert.NotEmpty(result); + } + + [Fact] + public void TestBuildStringToSign() + { + string expectedCanonicalHash = "foo"; + StringBuilder expectedStringBuilder = new StringBuilder(); + expectedStringBuilder.Append("AWS4-HMAC-SHA256" + "\n"); + expectedStringBuilder.Append(ISOSigningDateTime + "\n"); + expectedStringBuilder.AppendFormat("{0}/{1}/execute-api/aws4_request\n", ISOSigningDate, TestRegion); + expectedStringBuilder.Append(expectedCanonicalHash); + + string result = awsSignerHelperUnderTest.BuildStringToSign(SigningDate, expectedCanonicalHash, TestRegion); + + Assert.Equal(expectedStringBuilder.ToString(), result); + } + + [Fact] + public void TestInitializeHeadersReturnsUtcNow() + { + Assert.Equal(SigningDate, awsSignerHelperUnderTest.SetDateAndHostHeaders(new RestRequest(), TestHost)); + } + + [Fact] + public void TestInitializeHeadersSetsUtcNowXAmzDateHeader() + { + IRestRequest request = new RestRequest(); + awsSignerHelperUnderTest.SetDateAndHostHeaders(request, TestHost); + + Parameter actualParameter = request.Parameters.Find(parameter => + ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.XAmzDateHeaderName); + + Assert.Equal(ISOSigningDateTime, actualParameter.Value); + } + + [Fact] + public void TestInitializeHeadersOverwritesXAmzDateHeader() + { + IRestRequest request = new RestRequest(); + request.AddHeader(AWSSignerHelper.XAmzDateHeaderName, "foobar"); + + awsSignerHelperUnderTest.SetDateAndHostHeaders(request, TestHost); + + Parameter actualParameter = request.Parameters.Find(parameter => + ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.XAmzDateHeaderName); + + Assert.Equal(ISOSigningDateTime, actualParameter.Value); + } + + [Fact] + public void TestAddSignatureToRequest() + { + IRestRequest restRequest = new RestRequest(); + string expectedAccessKeyId = TestAccessKeyId; + string expectedRegion = TestRegion; + string expectedSignature = "testCalculatedSignature"; + string expectedSignedHeaders = "header1;header2"; + + string expectedAuthorizationHeaderValue = string.Format("AWS4-HMAC-SHA256 " + + "Credential={0}/{1}/{2}/execute-api/aws4_request, SignedHeaders={3}, Signature={4}", + expectedAccessKeyId, + ISOSigningDate, + expectedRegion, + expectedSignedHeaders, + expectedSignature); + + awsSignerHelperUnderTest.AddSignature(restRequest, + expectedAccessKeyId, + expectedSignedHeaders, + expectedSignature, + expectedRegion, + SigningDate); + + Parameter actualParameter = restRequest.Parameters.Find(parameter => + ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.AuthorizationHeaderName); + + Assert.Equal(expectedAuthorizationHeaderValue, actualParameter.Value); + } + + [Fact] + public void TestCalculateSignature() + { + string signature = awsSignerHelperUnderTest.CalculateSignature("testString", + SigningDate, + TestSecretKey, + TestRegion); + Assert.Equal("7e2c7c2e330123ef7468b41d8ddaf3841e6ef56959b9116b44ded5466cf96405", signature); + } + + [Fact] + public void TestInitializeHeadersSetsHostHeader() + { + IRestRequest restRequest = new RestRequest(); + + awsSignerHelperUnderTest.SetDateAndHostHeaders(restRequest, TestHost); + + Parameter actualParamter = restRequest.Parameters.Find(parameter => + ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.HostHeaderName); + + Assert.Equal(TestHost, actualParamter.Value); + } + + [Fact] + public void TestInitializeHeadersOverwritesHostHeader() + { + IRestRequest restRequest = new RestRequest(); + + restRequest.AddHeader(AWSSignerHelper.HostHeaderName, "foobar"); + + awsSignerHelperUnderTest.SetDateAndHostHeaders(restRequest, TestHost); + + Parameter actualParamter = restRequest.Parameters.Find(parameter => + ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.HostHeaderName); + + Assert.Equal(TestHost, actualParamter.Value); + } + + [Fact] + public void TestSetSessionHeader() + { + IRestRequest restRequest = new RestRequest(); + + restRequest.AddHeader(AWSSignerHelper.SecurityTokenHeaderName, "testName"); + + awsSignerHelperUnderTest.SetSessionTokenHeader(restRequest, TestSessionToken); + + Parameter actualParameter = restRequest.Parameters.Find(parameter => + ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.SecurityTokenHeaderName); + + Assert.Equal(TestSessionToken, actualParameter.Value); + } + } +} diff --git a/clients/sellingpartner-api-aa-java/pom.xml b/clients/sellingpartner-api-aa-java/pom.xml index 4277e068..d3d15068 100644 --- a/clients/sellingpartner-api-aa-java/pom.xml +++ b/clients/sellingpartner-api-aa-java/pom.xml @@ -89,7 +89,6 @@ 5.9.2 test - org.junit.jupiter @@ -126,7 +125,7 @@ com.google.guava guava - 30.1-jre + 32.0.0-jre diff --git a/clients/sellingpartner-api-aa-javascript/README.md b/clients/sellingpartner-api-aa-javascript/README.md index 70e3b3df..2ec8ba68 100644 --- a/clients/sellingpartner-api-aa-javascript/README.md +++ b/clients/sellingpartner-api-aa-javascript/README.md @@ -4,8 +4,8 @@ This library is to help SP-API developers to create an app in JavaScript on Node.js easier than calling HTTP endpoints directly. This library comes with the following features. 1. Login with Amazon (LWA) helper that does OAuth token refresh flow. 2. This library takes care of HTTP communication with SP-API endpoints with a help of [superagent](https://www.npmjs.com/package/superagent), so you can call SP-API by just calling a right method of library that corresponds to SP-API operation. -3. Calling SP-API requires non-standard `x-amz-access-token` HTTP request header in request. The SDK generated by this library supports to include this header with token value you specify. -4. SP-API operaitons to handle restricted data are categorized as ["Restricted Operations"](https://developer-docs.amazon.com/sp-api/lang-ja_JP/docs/tokens-api-use-case-guide#restricted-operations), which requires ["Restricted Data Token" (RDT)](https://developer-docs.amazon.com/sp-api/lang-ja_JP/docs/authorization-with-the-restricted-data-token) instead of access token for tighter security. Calling restricted operation involves two seprate steps, one of wihch is calling Tokens API to retrieve RDT and the other of which is calling protected operation with RDT. This library helps to compbine these two steps into single library call. +3. Calling SP-API requires non-standard `x-amz-access-token` HTTP request header in the request. The SDK generated by this library supports to include this header with the token value you specify. +4. SP-API operations to handle restricted data are categorized as ["Restricted Operations"](https://developer-docs.amazon.com/sp-api/lang-ja_JP/docs/tokens-api-use-case-guide#restricted-operations), which requires ["Restricted Data Token" (RDT)](https://developer-docs.amazon.com/sp-api/lang-ja_JP/docs/authorization-with-the-restricted-data-token) instead of access token for tighter security. Calling restricted operation involves two separate steps, one of which is calling Tokens API to retrieve RDT and the other of which is calling protected operation with RDT. This library helps to combine these two steps into a single library call. ## Installation and Generating SDK Please note this library doesn't include SDK. You need to generate SDK with the template and script files included in this library. @@ -17,7 +17,7 @@ Please note this library doesn't include SDK. You need to generate SDK with the __CAUTION__: Please be aware that there are two major known issues with the latest JavaScript client library. 1. If you use swagger-codegen-cli newer than 2.4.29 (such as 2.4.30 or 3.x), there is a known compatibility issue with SP-API models that makes generating SDK fail. We recommend that you use swagger-codegen-cli-2.4.29 specifically. -2. Swagger codegen tool fails to generate SDK for "Merchant Fulfillment V0 API." For workaround, you need to modify a part of the API model file "merchantFulfillmentV0.json" +2. Swagger codegen tool fails to generate SDK for "Merchant Fulfillment V0 API." For a workaround, you need to modify a part of the API model file "merchantFulfillmentV0.json" ### Download swagger-codegen-cli JAR file We use `swagger-codegen-cli` executable JAR file. You can download it by the following command. @@ -41,14 +41,14 @@ You will find `models` directory and `sdk` directory under the package root.
* `models`: directory contains API models cloned from SP-API GitHub. * `sdk`: directory contains generated JavaScript SDK. -### Modify Merchant Fulfillment API model file to avoid error during SDK generation -If you want to call Merchant Fulfillment API with the generated SDK, you need to follow this instruction. There is an fatal known issue in generating Merchant Fulfillment API library. If downloading API models is successful, you should be able to find `merchantFulfillmentV0.json` file In `/models/merchant-fulfillment-api-model` directory. Open this file with an editor and find the following part. +### Modify Merchant Fulfillment API model file to avoid errors during SDK generation +If you want to call Merchant Fulfillment API with the generated SDK, you need to follow this instruction. There is a fatal known issue in generating Merchant Fulfillment API library. If downloading API models is successful, you should be able to find `merchantFulfillmentV0.json` file In `/models/merchant-fulfillment-api-model` directory. Open this file with an editor and find the following part. ``` "AvailableFormatOptionsForLabel": { "$ref": "#/definitions/AvailableFormatOptionsForLabelList" }, ``` -Since this part causes a fatal error in SDK generation for JavaScript, please replace this part with the following snipet. +Since this part causes a fatal error in SDK generation for JavaScript, please replace this part with the following snippet. ``` "AvailableFormatOptionsForLabel": { "type": "array", @@ -67,7 +67,7 @@ Found /models already exists. Would you like to delete all the fil With the correct modification in `merchantFulfillmentV0.json`, you should be able to find generated SDK for Merchant Fulfillment API. ### How to run tests -This library contains a sample programs in `sample_node_app` directory under the packagte root.
In order to run the program, you need to have LWA credential information saved in the file and name it `app.config.mjs` and put it `/src` directory. Because __client secret__ and __refresh token__ shouldn't be exposed, you must make sure that you don't commit this file to the repository. +This library contains sample programs in `sample_node_app` directory under the package root.
In order to run the program, you need to have LWA credential information saved in the file and name it `app.config.mjs` and put it `/src` directory. Because __client secret__ and __refresh token__ shouldn't be exposed, you must make sure that you don't commit this file to the repository. ```javascript export const AppConfig = { lwaClientId: "< LWA client ID >", @@ -101,7 +101,7 @@ ordersApiClient.enableAutoRetrievalRestrictedDataToken("", const ordersApi = new OrdersV0Api(ordersApiClient); const order = await ordersApi.getOrder(""); ``` -### Calling SP-API with access token +### Calling SP-API with the access token In case you manage LWA token refresh flow, you can explicitly use the access token you got yourself for your SP-API call as follows. ```javascript import { SellersApi, ApiClient as SellersApiClient } from '../../sdk/src/sellers/index.js'; @@ -112,10 +112,10 @@ sellerApiClient.applyXAmzAccessTokenToRequest(""; const lwaClient = new LwaAuthClient("", "", ""); const accessToken = await lwaClient.getAccessToken(); -``` \ No newline at end of file +``` diff --git a/clients/sellingpartner-api-aa-python/requirements.txt b/clients/sellingpartner-api-aa-python/requirements.txt index 7c107f35..33da67a3 100644 --- a/clients/sellingpartner-api-aa-python/requirements.txt +++ b/clients/sellingpartner-api-aa-python/requirements.txt @@ -24,7 +24,7 @@ python-dateutil==2.8.2 pytz==2023.3 PyYAML==6.0 referencing==0.29.1 -requests==2.31.0 +requests==2.32.2 rfc3339-validator==0.1.4 rfc3987==1.3.8 rpds-py==0.8.10 diff --git a/models/.DS_Store b/models/.DS_Store new file mode 100644 index 00000000..cd5aa68a Binary files /dev/null and b/models/.DS_Store differ diff --git a/models/fba-small-and-light-api-model/fbaSmallandLight.json b/models/fba-small-and-light-api-model/fbaSmallandLight.json new file mode 100644 index 00000000..b5e5aac9 --- /dev/null +++ b/models/fba-small-and-light-api-model/fbaSmallandLight.json @@ -0,0 +1,2271 @@ +{ + "swagger": "2.0", + "info": { + "description": "The Selling Partner API for FBA Small and Light lets you help sellers manage their listings in the Small and Light program. The program reduces the cost of fulfilling orders for small and lightweight FBA inventory. You can enroll or remove items from the program and check item eligibility and enrollment status. You can also preview the estimated program fees charged to a seller for items sold while enrolled in the program. \n\n**Note:** The FBA Small and Light program sunset in the US and EU regions on **September 26, 2023**. The program will be deprecated in the JP region on **March 31, 2024** and sunset on **April 1, 2024**. APIs announcing deprecation will no longer be supported after their deprecation date. Calls to deprecated APIs will fail beginning on their sunset date. For more information, refer to [FBA Small and Light program deprecation](https://developer-docs.amazon.com/sp-api/changelog/fba-small-and-light-program-deprecation).", + "version": "v1", + "title": "Selling Partner API for FBA Small And Light", + "contact": { + "name": "Selling Partner API Developer Support", + "url": "https://sellercentral.amazon.com/gp/mws/contactus.html" + }, + "license": { + "name": "Apache License 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0" + } + }, + "host": "sellingpartnerapi-na.amazon.com", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/fba/smallAndLight/v1/enrollments/{sellerSKU}": { + "get": { + "tags": [ + "smallAndLight" + ], + "description": "Returns the Small and Light enrollment status for the item indicated by the specified seller SKU in the specified marketplace.\n\n**Usage Plan:**\n\n| Rate (requests per second) | Burst |\n| ---- | ---- |\n| 2 | 10 |\n\nThe `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may see higher rate and burst values than those shown here. For more information, see [Usage Plans and Rate Limits in the Selling Partner API](https://developer-docs.amazon.com/sp-api/docs/usage-plans-and-rate-limits-in-the-sp-api).", + "operationId": "getSmallAndLightEnrollmentBySellerSKU", + "deprecated": true, + "parameters": [ + { + "name": "sellerSKU", + "in": "path", + "description": "The seller SKU that identifies the item.", + "required": true, + "type": "string" + }, + { + "name": "marketplaceIds", + "in": "query", + "description": "The marketplace for which the enrollment status is retrieved. Note: Accepts a single marketplace only.", + "required": true, + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 1 + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/SmallAndLightEnrollment" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_ENROLLED_IN_SMALL_AND_LIGHT" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "marketplaceId": "ATVPDKIKX0DER", + "sellerSKU": "SKU_ENROLLED_IN_SMALL_AND_LIGHT", + "status": "ENROLLED" + } + } + ] + } + }, + "400": { + "description": "Request has missing or invalid parameters and cannot be parsed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_400" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "InvalidInput", + "message": "Invalid input." + } + ] + } + } + ] + } + }, + "403": { + "description": "Indicates that access to the resource is forbidden. Possible reasons include Access Denied, Unauthorized, Expired Token, or Invalid Signature.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_403" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "Unauthorized", + "message": "Access to requested resource is denied." + } + ] + } + } + ] + } + }, + "404": { + "description": "The resource specified does not exist.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_404" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "NotFound", + "message": "Requested resource is not found" + } + ] + } + } + ] + } + }, + "413": { + "description": "The request size exceeded the maximum accepted size.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_413" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "PayloadTooLarge", + "message": "Payload of the request is too large." + } + ] + } + } + ] + } + }, + "415": { + "description": "The request payload is in an unsupported format.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_415" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "UnsupportedType", + "message": "The entity of the request is of unsupported type." + } + ] + } + } + ] + } + }, + "429": { + "description": "The frequency of requests was greater than allowed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_429" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "TooManyRequests", + "message": "Total number of requests exceed your allowed limits." + } + ] + } + } + ] + } + }, + "500": { + "description": "An unexpected condition occurred that prevented the server from fulfilling the request.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_500" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "InternalServerError", + "message": "Server encountered an unexpected condition while processing your request." + } + ] + } + } + ] + } + }, + "503": { + "description": "Temporary overloading or maintenance of the server.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_503" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "ServiceUnavailable", + "message": "Server is temporarily unavailable." + } + ] + } + } + ] + } + } + } + }, + "put": { + "tags": [ + "smallAndLight" + ], + "description": "Enrolls the item indicated by the specified seller SKU in the Small and Light program in the specified marketplace. If the item is not eligible, the ineligibility reasons are returned.\n\n**Usage Plan:**\n\n| Rate (requests per second) | Burst |\n| ---- | ---- |\n| 2 | 5 |\n\nThe `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may see higher rate and burst values than those shown here. For more information, see [Usage Plans and Rate Limits in the Selling Partner API](https://developer-docs.amazon.com/sp-api/docs/usage-plans-and-rate-limits-in-the-sp-api).", + "operationId": "putSmallAndLightEnrollmentBySellerSKU", + "deprecated": true, + "parameters": [ + { + "name": "sellerSKU", + "in": "path", + "description": "The seller SKU that identifies the item.", + "required": true, + "type": "string" + }, + { + "name": "marketplaceIds", + "in": "query", + "description": "The marketplace in which to enroll the item. Note: Accepts a single marketplace only.", + "required": true, + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 1 + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/SmallAndLightEnrollment" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_ELIGIBLE_FOR_SMALL_AND_LIGHT" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "marketplaceId": "ATVPDKIKX0DER", + "sellerSKU": "SKU_ELIGIBLE_FOR_SMALL_AND_LIGHT", + "status": "ENROLLED" + } + } + ] + } + }, + "400": { + "description": "Request has missing or invalid parameters and cannot be parsed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_400" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "InvalidInput", + "message": "Invalid input." + } + ] + } + } + ] + } + }, + "403": { + "description": "Indicates that access to the resource is forbidden. Possible reasons include Access Denied, Unauthorized, Expired Token, or Invalid Signature.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_403" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "Unauthorized", + "message": "Access to requested resource is denied." + } + ] + } + } + ] + } + }, + "404": { + "description": "The resource specified does not exist.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_404" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "NotFound", + "message": "Requested resource is not found" + } + ] + } + } + ] + } + }, + "413": { + "description": "The request size exceeded the maximum accepted size.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_413" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "PayloadTooLarge", + "message": "Payload of the request is too large." + } + ] + } + } + ] + } + }, + "415": { + "description": "The request payload is in an unsupported format.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_415" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "UnsupportedType", + "message": "The entity of the request is of unsupported type." + } + ] + } + } + ] + } + }, + "429": { + "description": "The frequency of requests was greater than allowed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_429" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "TooManyRequests", + "message": "Total number of requests exceed your allowed limits." + } + ] + } + } + ] + } + }, + "500": { + "description": "An unexpected condition occurred that prevented the server from fulfilling the request.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_500" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "InternalServerError", + "message": "Server encountered an unexpected condition while processing your request." + } + ] + } + } + ] + } + }, + "503": { + "description": "Temporary overloading or maintenance of the server.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_503" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "ServiceUnavailable", + "message": "Server is temporarily unavailable." + } + ] + } + } + ] + } + } + } + }, + "delete": { + "tags": [ + "smallAndLight" + ], + "description": "Removes the item indicated by the specified seller SKU from the Small and Light program in the specified marketplace. If the item is not eligible for disenrollment, the ineligibility reasons are returned.\n\n**Usage Plan:**\n\n| Rate (requests per second) | Burst |\n| ---- | ---- |\n| 2 | 5 |\n\nThe `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may see higher rate and burst values than those shown here. For more information, see [Usage Plans and Rate Limits in the Selling Partner API](https://developer-docs.amazon.com/sp-api/docs/usage-plans-and-rate-limits-in-the-sp-api).", + "operationId": "deleteSmallAndLightEnrollmentBySellerSKU", + "deprecated": true, + "parameters": [ + { + "name": "sellerSKU", + "in": "path", + "description": "The seller SKU that identifies the item.", + "required": true, + "type": "string" + }, + { + "name": "marketplaceIds", + "in": "query", + "description": "The marketplace in which to remove the item from the Small and Light program. Note: Accepts a single marketplace only.", + "required": true, + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 1 + } + ], + "responses": { + "204": { + "description": "Success.", + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_ENROLLED_FOR_SMALL_AND_LIGHT" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": {} + } + ] + } + }, + "400": { + "description": "Request has missing or invalid parameters and cannot be parsed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_400" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "InvalidInput", + "message": "Invalid input." + } + ] + } + } + ] + } + }, + "403": { + "description": "Indicates that access to the resource is forbidden. Possible reasons include Access Denied, Unauthorized, Expired Token, or Invalid Signature.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_403" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "Unauthorized", + "message": "Access to requested resource is denied." + } + ] + } + } + ] + } + }, + "404": { + "description": "The resource specified does not exist.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_404" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "NotFound", + "message": "Requested resource is not found" + } + ] + } + } + ] + } + }, + "413": { + "description": "The request size exceeded the maximum accepted size.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_413" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "PayloadTooLarge", + "message": "Payload of the request is too large." + } + ] + } + } + ] + } + }, + "415": { + "description": "The request payload is in an unsupported format.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_415" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "UnsupportedType", + "message": "The entity of the request is of unsupported type." + } + ] + } + } + ] + } + }, + "429": { + "description": "The frequency of requests was greater than allowed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_429" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "TooManyRequests", + "message": "Total number of requests exceed your allowed limits." + } + ] + } + } + ] + } + }, + "500": { + "description": "An unexpected condition occurred that prevented the server from fulfilling the request.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_500" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "InternalServerError", + "message": "Server encountered an unexpected condition while processing your request." + } + ] + } + } + ] + } + }, + "503": { + "description": "Temporary overloading or maintenance of the server.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_503" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "ServiceUnavailable", + "message": "Server is temporarily unavailable." + } + ] + } + } + ] + } + } + } + } + }, + "/fba/smallAndLight/v1/eligibilities/{sellerSKU}": { + "get": { + "tags": [ + "smallAndLight" + ], + "description": "Returns the Small and Light program eligibility status of the item indicated by the specified seller SKU in the specified marketplace. If the item is not eligible, the ineligibility reasons are returned. **Note:** The parameters associated with this operation may contain special characters that must be encoded to successfully call the API. To avoid errors with SKUs when encoding URLs, refer to [URL Encoding](https://developer-docs.amazon.com/sp-api/docs/url-encoding).\n\n**Usage Plan:**\n\n| Rate (requests per second) | Burst |\n| ---- | ---- |\n| 2 | 10 |\n\nThe `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may see higher rate and burst values than those shown here. For more information, see [Usage Plans and Rate Limits in the Selling Partner API](https://developer-docs.amazon.com/sp-api/docs/usage-plans-and-rate-limits-in-the-sp-api).", + "operationId": "getSmallAndLightEligibilityBySellerSKU", + "deprecated": true, + "parameters": [ + { + "name": "sellerSKU", + "in": "path", + "description": "The seller SKU that identifies the item.", + "required": true, + "type": "string" + }, + { + "name": "marketplaceIds", + "in": "query", + "description": "The marketplace for which the eligibility status is retrieved. NOTE: Accepts a single marketplace only.", + "required": true, + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 1 + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/SmallAndLightEligibility" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_ELIGIBLE_FOR_SMALL_AND_LIGHT" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "marketplaceId": "ATVPDKIKX0DER", + "sellerSKU": "SKU_ELIGIBLE_FOR_SMALL_AND_LIGHT", + "status": "ELIGIBLE" + } + } + ] + } + }, + "400": { + "description": "Request has missing or invalid parameters and cannot be parsed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_400" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "InvalidInput", + "message": "Invalid input." + } + ] + } + } + ] + } + }, + "403": { + "description": "Indicates that access to the resource is forbidden. Possible reasons include Access Denied, Unauthorized, Expired Token, or Invalid Signature.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_403" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "Unauthorized", + "message": "Access to requested resource is denied." + } + ] + } + } + ] + } + }, + "404": { + "description": "The resource specified does not exist.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_404" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "NotFound", + "message": "Requested resource is not found" + } + ] + } + } + ] + } + }, + "413": { + "description": "The request size exceeded the maximum accepted size.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_413" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "PayloadTooLarge", + "message": "Payload of the request is too large." + } + ] + } + } + ] + } + }, + "415": { + "description": "The request payload is in an unsupported format.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_415" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "UnsupportedType", + "message": "The entity of the request is of unsupported type." + } + ] + } + } + ] + } + }, + "429": { + "description": "The frequency of requests was greater than allowed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_429" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "TooManyRequests", + "message": "Total number of requests exceed your allowed limits." + } + ] + } + } + ] + } + }, + "500": { + "description": "An unexpected condition occurred that prevented the server from fulfilling the request.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_500" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "InternalServerError", + "message": "Server encountered an unexpected condition while processing your request." + } + ] + } + } + ] + } + }, + "503": { + "description": "Temporary overloading or maintenance of the server.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "sellerSKU": { + "value": "SKU_503" + }, + "marketplaceIds": { + "value": [ + "ATVPDKIKX0DER" + ] + } + } + }, + "response": { + "errors": [ + { + "code": "ServiceUnavailable", + "message": "Server is temporarily unavailable." + } + ] + } + } + ] + } + } + } + } + }, + "/fba/smallAndLight/v1/feePreviews": { + "post": { + "tags": [ + "smallAndLight" + ], + "description": "Returns the Small and Light fee estimates for the specified items. You must include a marketplaceId parameter to retrieve the proper fee estimates for items to be sold in that marketplace. The ordering of items in the response will mirror the order of the items in the request. Duplicate ASIN/price combinations are removed.\n\n**Usage Plan:**\n\n| Rate (requests per second) | Burst |\n| ---- | ---- |\n| 1 | 3 |\n\nThe `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may see higher rate and burst values than those shown here. For more information, see [Usage Plans and Rate Limits in the Selling Partner API](https://developer-docs.amazon.com/sp-api/docs/usage-plans-and-rate-limits-in-the-sp-api).", + "operationId": "getSmallAndLightFeePreview", + "deprecated": true, + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SmallAndLightFeePreviewRequest" + } + } + ], + "responses": { + "200": { + "description": "Success.", + "schema": { + "$ref": "#/definitions/SmallAndLightFeePreviews" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "body": { + "value": { + "marketplaceId": "ATVPDKIKX0DER", + "items": [ + { + "asin": "B076ZL9PB5", + "price": { + "currencyCode": "USD", + "amount": 6.5 + } + } + ] + } + } + } + }, + "response": { + "data": [ + { + "asin": "B076ZL9PB5", + "price": { + "amount": 6.5, + "currencyCode": "USD" + }, + "feeBreakdown": [ + { + "feeType": "FBAPerUnitFulfillmentFee", + "feeCharge": { + "amount": 0.75, + "currencyCode": "USD" + } + }, + { + "feeType": "FBAPerOrderFulfillmentFee", + "feeCharge": { + "amount": 1, + "currencyCode": "USD" + } + }, + { + "feeType": "FBAWeightBasedFee", + "feeCharge": { + "amount": 1.1, + "currencyCode": "USD" + } + }, + { + "feeType": "Commission", + "feeCharge": { + "amount": 0.98, + "currencyCode": "USD" + } + } + ], + "totalFees": { + "amount": 3.83, + "currencyCode": "USD" + }, + "errors": [] + } + ] + } + } + ] + } + }, + "400": { + "description": "Request has missing or invalid parameters and cannot be parsed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "body": { + "value": { + "marketplaceId": "TEST_CASE_400", + "items": [] + } + } + } + }, + "response": { + "errors": [ + { + "code": "InvalidInput", + "message": "Invalid input." + } + ] + } + } + ] + } + }, + "401": { + "description": "The request's Authorization header is not formatted correctly or does not contain a valid token.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "body": { + "value": { + "marketplaceId": "TEST_CASE_401", + "items": [] + } + } + } + }, + "response": { + "errors": [ + { + "code": "Unauthorized", + "message": "Access to requested resource is denied." + } + ] + } + } + ] + } + }, + "403": { + "description": "Indicates that access to the resource is forbidden. Possible reasons include Access Denied, Unauthorized, Expired Token, or Invalid Signature.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "body": { + "value": { + "marketplaceId": "TEST_CASE_403", + "items": [] + } + } + } + }, + "response": { + "errors": [ + { + "code": "Unauthorized", + "message": "Access to requested resource is denied." + } + ] + } + } + ] + } + }, + "404": { + "description": "The resource specified does not exist.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "body": { + "value": { + "marketplaceId": "TEST_CASE_404", + "items": [] + } + } + } + }, + "response": { + "errors": [ + { + "code": "NotFound", + "message": "The requested resource doesn't exist." + } + ] + } + } + ] + } + }, + "429": { + "description": "The frequency of requests was greater than allowed.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "body": { + "value": { + "marketplaceId": "TEST_CASE_429", + "items": [] + } + } + } + }, + "response": { + "errors": [ + { + "code": "QuotaExceeded", + "message": "You exceeded your quota for the requested resource." + } + ] + } + } + ] + } + }, + "500": { + "description": "An unexpected condition occurred that prevented the server from fulfilling the request.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "body": { + "value": { + "marketplaceId": "TEST_CASE_500", + "items": [] + } + } + } + }, + "response": { + "errors": [ + { + "code": "InternalFailure", + "message": "We encountered an internal error. Please try again." + } + ] + } + } + ] + } + }, + "503": { + "description": "Temporary overloading or maintenance of the server.", + "schema": { + "$ref": "#/definitions/ErrorList" + }, + "headers": { + "x-amzn-RateLimit-Limit": { + "type": "string", + "description": "Your rate limit (requests per second) for this operation.\n_Note:_ For this status code, the rate limit header is deprecated and no longer returned." + }, + "x-amzn-RequestId": { + "type": "string", + "description": "Unique request reference identifier." + } + }, + "x-amzn-api-sandbox": { + "static": [ + { + "request": { + "parameters": { + "body": { + "value": { + "marketplaceId": "TEST_CASE_503", + "items": [] + } + } + } + }, + "response": { + "errors": [ + { + "code": "ServiceUnavailable", + "message": "Service is temporarily unavailable. Please try again." + } + ] + } + } + ] + } + } + } + } + } + }, + "definitions": { + "MarketplaceId": { + "type": "string", + "description": "A marketplace identifier." + }, + "SellerSKU": { + "type": "string", + "description": "Identifies an item in the given marketplace. SellerSKU is qualified by the seller's SellerId, which is included with every operation that you submit." + }, + "Error": { + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "string", + "description": "An error code that identifies the type of error that occurred." + }, + "message": { + "type": "string", + "description": "A message that describes the error condition." + }, + "details": { + "type": "string", + "description": "Additional details that can help the caller understand or fix the issue." + } + }, + "description": "Error response returned when the request is unsuccessful." + }, + "ErrorList": { + "type": "object", + "properties": { + "errors": { + "type": "array", + "items": { + "$ref": "#/definitions/Error" + } + } + }, + "description": "A list of error responses returned when a request is unsuccessful." + }, + "SmallAndLightEnrollmentStatus": { + "type": "string", + "description": "The Small and Light enrollment status of the item.", + "enum": [ + "ENROLLED", + "NOT_ENROLLED" + ], + "x-docgen-enum-table-extension": [ + { + "value": "ENROLLED", + "description": "The Small and Light enrollment status is enrolled." + }, + { + "value": "NOT_ENROLLED", + "description": "The Small and Light enrollment status is not enrolled." + } + ] + }, + "SmallAndLightEligibilityStatus": { + "type": "string", + "description": "The Small and Light eligibility status of the item.", + "enum": [ + "ELIGIBLE", + "NOT_ELIGIBLE" + ], + "x-docgen-enum-table-extension": [ + { + "value": "ELIGIBLE", + "description": "The Small and Light eligibility status is eligible." + }, + { + "value": "NOT_ELIGIBLE", + "description": "The Small and Light eligibility status is not eligible." + } + ] + }, + "SmallAndLightEnrollment": { + "type": "object", + "required": [ + "marketplaceId", + "sellerSKU", + "status" + ], + "properties": { + "marketplaceId": { + "$ref": "#/definitions/MarketplaceId" + }, + "sellerSKU": { + "$ref": "#/definitions/SellerSKU" + }, + "status": { + "$ref": "#/definitions/SmallAndLightEnrollmentStatus" + } + }, + "description": "The Small and Light enrollment status of the item indicated by the specified seller SKU." + }, + "SmallAndLightEligibility": { + "type": "object", + "required": [ + "marketplaceId", + "sellerSKU", + "status" + ], + "properties": { + "marketplaceId": { + "$ref": "#/definitions/MarketplaceId" + }, + "sellerSKU": { + "$ref": "#/definitions/SellerSKU" + }, + "status": { + "$ref": "#/definitions/SmallAndLightEligibilityStatus" + } + }, + "description": "The Small and Light eligibility status of the item indicated by the specified seller SKU." + }, + "SmallAndLightFeePreviewRequest": { + "type": "object", + "required": [ + "items", + "marketplaceId" + ], + "properties": { + "marketplaceId": { + "$ref": "#/definitions/MarketplaceId" + }, + "items": { + "type": "array", + "description": "A list of items for which to retrieve fee estimates (limit: 25).", + "items": { + "$ref": "#/definitions/Item" + }, + "maxItems": 25 + } + }, + "description": "Request schema for submitting items for which to retrieve fee estimates." + }, + "SmallAndLightFeePreviews": { + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "A list of fee estimates for the requested items. The order of the fee estimates will follow the same order as the items in the request, with duplicates removed.", + "items": { + "$ref": "#/definitions/FeePreview" + } + } + } + }, + "Item": { + "type": "object", + "required": [ + "asin", + "price" + ], + "properties": { + "asin": { + "type": "string", + "description": "The Amazon Standard Identification Number (ASIN) value used to identify the item." + }, + "price": { + "description": "The price that the seller plans to charge for the item.", + "$ref": "#/definitions/MoneyType" + } + }, + "description": "An item to be sold." + }, + "FeePreview": { + "type": "object", + "properties": { + "asin": { + "type": "string", + "description": "The Amazon Standard Identification Number (ASIN) value used to identify the item." + }, + "price": { + "description": "The price that the seller plans to charge for the item.", + "$ref": "#/definitions/MoneyType" + }, + "feeBreakdown": { + "type": "array", + "description": "A list of the Small and Light fees for the item.", + "items": { + "$ref": "#/definitions/FeeLineItem" + } + }, + "totalFees": { + "description": "The total fees charged if the item participated in the Small and Light program.", + "$ref": "#/definitions/MoneyType" + }, + "errors": { + "type": "array", + "description": "One or more unexpected errors occurred during the getSmallAndLightFeePreview operation.", + "items": { + "$ref": "#/definitions/Error" + } + } + }, + "description": "The fee estimate for a specific item." + }, + "FeeLineItem": { + "type": "object", + "required": [ + "feeCharge", + "feeType" + ], + "properties": { + "feeType": { + "type": "string", + "description": "The type of fee charged to the seller.", + "enum": [ + "FBAWeightBasedFee", + "FBAPerOrderFulfillmentFee", + "FBAPerUnitFulfillmentFee", + "Commission" + ], + "x-docgen-enum-table-extension": [ + { + "value": "FBAWeightBasedFee", + "description": "The FBA weight-based fee (weight handling)." + }, + { + "value": "FBAPerOrderFulfillmentFee", + "description": "The FBA per-order fulfillment fee (order handling)." + }, + { + "value": "FBAPerUnitFulfillmentFee", + "description": "The FBA fulfillment fee (Pick & Pack)." + }, + { + "value": "Commission", + "description": "The commission - referral fee." + } + ] + }, + "feeCharge": { + "description": "Amount charged to the seller for the specific fee type.", + "$ref": "#/definitions/MoneyType" + } + }, + "description": "Fee details for a specific fee." + }, + "MoneyType": { + "type": "object", + "properties": { + "currencyCode": { + "type": "string", + "description": "The currency code in ISO 4217 format." + }, + "amount": { + "type": "number", + "description": "The monetary value." + } + } + } + } +} \ No newline at end of file diff --git a/schemas/notifications/AnyOfferChangedNotification.json b/schemas/notifications/AnyOfferChangedNotification.json index baa0f0be..29026d0e 100644 --- a/schemas/notifications/AnyOfferChangedNotification.json +++ b/schemas/notifications/AnyOfferChangedNotification.json @@ -4,10 +4,9 @@ "type": "object", "title": "The root schema", "description": "The root schema comprises the entire JSON document.", - "default": {}, "examples": [ { - "NotificatonTionVersion": "1.0", + "NotificationVersion": "1.0", "NotificationType": "ANY_OFFER_CHANGED", "PayloadVersion": "1.0", "EventTime": "2020-07-13T19:42:04.284Z", @@ -182,6 +181,7 @@ "State": "MI" }, "IsFulfilledByAmazon": true, + "IsBuyBoxWinner" : false, "PrimeInformation": { "IsOfferPrime": true, "IsOfferNationalPrime": false @@ -197,7 +197,7 @@ } ], "required": [ - "NotificatonTionVersion", + "NotificationVersion", "NotificationType", "PayloadVersion", "EventTime", @@ -206,10 +206,10 @@ ], "additionalProperties": true, "properties": { - "NotificatonTionVersion": { - "$id": "#/properties/NotificatonTionVersion", + "NotificationVersion": { + "$id": "#/properties/NotificationVersion", "type": "string", - "title": "The NotificatonTionVersion schema", + "title": "The NotificationVersion schema", "description": "An explanation about the purpose of this instance.", "default": "", "examples": [ @@ -251,7 +251,6 @@ "type": "object", "title": "The NotificationMetadata schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ApplicationId": "app-id-d0e9e693-c3ad-4373-979f-ed4ec98dd746", @@ -315,7 +314,6 @@ "type": "object", "title": "The Payload schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "AnyOfferChangedNotification": { @@ -482,6 +480,7 @@ "State": "MI" }, "IsFulfilledByAmazon": true, + "IsBuyBoxWinner" : false, "PrimeInformation": { "IsOfferPrime": true, "IsOfferNationalPrime": false @@ -505,7 +504,6 @@ "type": "object", "title": "The AnyOfferChangedNotification schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "SellerId": "A3TH9S8BH6GOGM", @@ -671,6 +669,7 @@ "State": "MI" }, "IsFulfilledByAmazon": true, + "IsBuyBoxWinner" : false, "PrimeInformation": { "IsOfferPrime": true, "IsOfferNationalPrime": false @@ -706,7 +705,6 @@ "type": "object", "title": "The OfferChangeTrigger schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "MarketplaceId": "ATVPDKIKX0DER", @@ -782,7 +780,6 @@ "type": "object", "title": "The Summary schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "NumberOfOffers": [ @@ -952,7 +949,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Condition": "new", @@ -1056,7 +1052,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Condition": "new", @@ -1109,7 +1104,6 @@ "type": "object", "title": "The LandedPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 10.0, @@ -1149,7 +1143,6 @@ "type": "object", "title": "The ListingPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 10.0, @@ -1189,7 +1182,6 @@ "type": "object", "title": "The Shipping schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 0.0, @@ -1231,7 +1223,6 @@ "type": "object", "title": "The second anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Condition": "old", @@ -1288,7 +1279,6 @@ "type": "object", "title": "The LandedPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 11.0, @@ -1328,7 +1318,6 @@ "type": "object", "title": "The ListingPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 20.0, @@ -1368,7 +1357,6 @@ "type": "object", "title": "The Shipping schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 40.0, @@ -1408,7 +1396,6 @@ "type": "object", "title": "The Points schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "PointsNumber": 34343 @@ -1488,7 +1475,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Condition": "new", @@ -1529,7 +1515,6 @@ "type": "object", "title": "The LandedPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 10.0, @@ -1569,7 +1554,6 @@ "type": "object", "title": "The ListingPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 10.0, @@ -1609,7 +1593,6 @@ "type": "object", "title": "The Shipping schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 0.0, @@ -1651,7 +1634,6 @@ "type": "object", "title": "The second anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Condition": "old", @@ -1696,7 +1678,6 @@ "type": "object", "title": "The LandedPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 11.0, @@ -1736,7 +1717,6 @@ "type": "object", "title": "The ListingPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 20.0, @@ -1776,7 +1756,6 @@ "type": "object", "title": "The Shipping schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 40.0, @@ -1816,7 +1795,6 @@ "type": "object", "title": "The Points schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "PointsNumber": 34343 @@ -1850,7 +1828,6 @@ "type": "object", "title": "The ListPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 55.0, @@ -1890,7 +1867,6 @@ "type": "object", "title": "The MinimumAdvertisedPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 66.0, @@ -1930,7 +1906,6 @@ "type": "object", "title": "The SuggestedLowerPricePlusShipping schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 77.0, @@ -2001,7 +1976,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ProductCategoryId": "1243", @@ -2068,7 +2042,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Condition": "new", @@ -2124,7 +2097,6 @@ "type": "object", "title": "The CompetitivePriceThreshold schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 22.0, @@ -2198,6 +2170,7 @@ "State": "MI" }, "IsFulfilledByAmazon": true, + "IsBuyBoxWinner" : false, "PrimeInformation": { "IsOfferPrime": true, "IsOfferNationalPrime": false @@ -2217,7 +2190,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "SellerId": "111", @@ -2248,6 +2220,7 @@ "State": "MI" }, "IsFulfilledByAmazon": true, + "IsBuyBoxWinner" : false, "PrimeInformation": { "IsOfferPrime": true, "IsOfferNationalPrime": false @@ -2268,6 +2241,7 @@ "Shipping", "ShipsFrom", "IsFulfilledByAmazon", + "IsBuyBoxWinner", "PrimeInformation", "IsExpeditedShippingAvailable", "IsFeaturedMerchant", @@ -2301,7 +2275,6 @@ "type": "object", "title": "The SellerFeedbackRating schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "FeedbackCount": 9, @@ -2341,7 +2314,6 @@ "type": "object", "title": "The ShippingTime schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "MinimumHours": 10, @@ -2405,7 +2377,6 @@ "type": "object", "title": "The ListingPrice schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 23.0, @@ -2445,7 +2416,6 @@ "type": "object", "title": "The Points schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "PointsNumber": 33333 @@ -2473,7 +2443,6 @@ "type": "object", "title": "The Shipping schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 110.0, @@ -2513,7 +2482,6 @@ "type": "object", "title": "The ShipsFrom schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Country": "USA", @@ -2558,12 +2526,21 @@ true ] }, + "IsBuyBoxWinner": { + "$id": "#/properties/Payload/properties/AnyOfferChangedNotification/properties/Offers/items/anyOf/0/properties/IsBuyBoxWinner", + "type": "boolean", + "title": "The IsBuyBoxWinner schema", + "description": "An explanation about the purpose of this instance.", + "default": false, + "examples": [ + true + ] + }, "PrimeInformation": { "$id": "#/properties/Payload/properties/AnyOfferChangedNotification/properties/Offers/items/anyOf/0/properties/PrimeInformation", "type": "object", "title": "The PrimeInformation schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "IsOfferPrime": true, @@ -2649,4 +2626,4 @@ } } } -} \ No newline at end of file +} diff --git a/schemas/notifications/BrandedItemContentChangeNotification.json b/schemas/notifications/BrandedItemContentChangeNotification.json index f14d93c8..92af14c3 100644 --- a/schemas/notifications/BrandedItemContentChangeNotification.json +++ b/schemas/notifications/BrandedItemContentChangeNotification.json @@ -4,7 +4,6 @@ "type": "object", "title": "The root schema", "description": "The root schema comprises the entire JSON document.", - "default": {}, "examples": [ { "NotificationVersion": "1.0", @@ -93,7 +92,6 @@ "type": "object", "title": "The Payload schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "MarketplaceId": "ATVPDKIKX0DER", @@ -185,7 +183,6 @@ "type": "object", "title": "The NotificationMetadata schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ApplicationId": "amzn1.sellerapps.app.f1234566-aaec-55a6-b123-bcb752069ec5", @@ -246,4 +243,4 @@ } }, "additionalProperties": true -} \ No newline at end of file +} diff --git a/schemas/notifications/FBAInventoryAvailabilityChangeNotification.json b/schemas/notifications/FBAInventoryAvailabilityChangeNotification.json index 35d6b8dd..2df302f5 100644 --- a/schemas/notifications/FBAInventoryAvailabilityChangeNotification.json +++ b/schemas/notifications/FBAInventoryAvailabilityChangeNotification.json @@ -4,7 +4,13 @@ "type": "object", "title": "The root schema", "description": "The root schema comprises the entire JSON document.", - "default": {}, + "required": [ + "NotificationVersion", + "NotificationType", + "PayloadVersion", + "EventTime", + "Payload" + ], "properties": { "NotificationVersion": { "$id": "#/properties/NotificationVersion", @@ -436,4 +442,4 @@ } }, "additionalProperties": true -} \ No newline at end of file +} diff --git a/schemas/notifications/FeePromotionNotification.json b/schemas/notifications/FeePromotionNotification.json index e770ba6f..c1ed4fa4 100644 --- a/schemas/notifications/FeePromotionNotification.json +++ b/schemas/notifications/FeePromotionNotification.json @@ -4,7 +4,6 @@ "type": "object", "title": "The root schema", "description": "The root schema comprises the entire JSON document.", - "default": {}, "examples": [ { "NotificationVersion": "1.0", @@ -395,7 +394,6 @@ "type": "object", "title": "The NotificationMetadata schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ApplicationId": "app-id-d0e9e693-c3ad-4373-979f-ed4ec98dd746", @@ -459,7 +457,6 @@ "type": "object", "title": "The Payload schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "FeePromotionNotification": { @@ -793,7 +790,6 @@ "type": "object", "title": "The FeePromotionNotification schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "MerchantId": "AJH434853485", @@ -1171,7 +1167,6 @@ "type": "object", "title": "The PromotionActiveTimeRange schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "EffectiveFromDate": "2020-07-13T19:42:04.284Z", @@ -1251,7 +1246,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "IdentifierType": "identifierType", @@ -1309,7 +1303,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "IdentifierValueId": "identifierValueId1", @@ -1652,7 +1645,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "FeeType": "FeeType", @@ -1839,7 +1831,6 @@ "type": "object", "title": "The PriceThreshold schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 60, @@ -1879,7 +1870,6 @@ "type": "object", "title": "The FeeDiscountMonetaryAmount schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 70, @@ -1919,7 +1909,6 @@ "type": "object", "title": "The FeesEstimate schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "TimeOfFeesEstimated": "2020-07-13T19:42:04.284Z", @@ -2070,7 +2059,6 @@ "type": "object", "title": "The TotalFeesEstimate schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 90, @@ -2242,7 +2230,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "FeeType": "feeType", @@ -2328,7 +2315,6 @@ "type": "object", "title": "The FeeAmount schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 10, @@ -2368,7 +2354,6 @@ "type": "object", "title": "The TaxAmount schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 20, @@ -2408,7 +2393,6 @@ "type": "object", "title": "The FeePromotion schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 30, @@ -2448,7 +2432,6 @@ "type": "object", "title": "The FinalFee schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 40, @@ -2540,7 +2523,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "FeeType": "feeType", @@ -2585,7 +2567,6 @@ "type": "object", "title": "The FeeAmount schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 10, @@ -2625,7 +2606,6 @@ "type": "object", "title": "The TaxAmount schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 20, @@ -2665,7 +2645,6 @@ "type": "object", "title": "The FeePromotion schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 30, @@ -2705,7 +2684,6 @@ "type": "object", "title": "The FinalFee schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "Amount": 40, @@ -2769,4 +2747,4 @@ } }, "additionalProperties": true -} \ No newline at end of file +} diff --git a/schemas/notifications/FulfillmentOrderStatusNotification.json b/schemas/notifications/FulfillmentOrderStatusNotification.json index 7e6d031f..2794e6e1 100644 --- a/schemas/notifications/FulfillmentOrderStatusNotification.json +++ b/schemas/notifications/FulfillmentOrderStatusNotification.json @@ -4,7 +4,6 @@ "type": "object", "title": "The root schema", "description": "The root schema comprises the entire JSON document.", - "default": {}, "examples": [ { "NotificationVersion": "1.0", @@ -114,7 +113,6 @@ "type": "object", "title": "The Payload schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "FulfillmentOrderStatusNotification": { @@ -167,7 +165,6 @@ "type": "object", "title": "The FulfillmentOrderStatusNotification schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "SellerId": "A3TH9S8BH6GOGM", @@ -274,7 +271,6 @@ "type": "object", "title": "The FulfillmentShipment schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "FulfillmentShipmentStatus": "PROCESSED", @@ -368,7 +364,6 @@ "type": "object", "title": "The info schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "PackageNumber": 1, @@ -425,7 +420,6 @@ "type": "object", "title": "The first anyOf schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "PackageNumber": 1, @@ -483,7 +477,6 @@ "type": "object", "title": "The FulfillmentReturnItem schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ReceivedDateTime": "2020-07-13T19:42:04.284Z", @@ -541,7 +534,6 @@ "type": "object", "title": "The NotificationMetadata schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ApplicationId": "app-id-d0e9e693-c3ad-4373-979f-ed4ec98dd746", @@ -602,4 +594,4 @@ } }, "additionalProperties": true -} \ No newline at end of file +} diff --git a/schemas/notifications/ItemProductTypeChangeNotification.json b/schemas/notifications/ItemProductTypeChangeNotification.json index a457e8f5..aad87a7d 100644 --- a/schemas/notifications/ItemProductTypeChangeNotification.json +++ b/schemas/notifications/ItemProductTypeChangeNotification.json @@ -4,7 +4,6 @@ "type": "object", "title": "The root schema", "description": "The root schema comprises the entire JSON document.", - "default": {}, "examples": [ { "NotificationVersion": "1.0", @@ -79,7 +78,6 @@ "type": "object", "title": "The Payload schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "MarketplaceId": "ATVPDKIKX0DER", @@ -143,7 +141,6 @@ "type": "object", "title": "The NotificationMetadata schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ApplicationId": "amzn1.sellerapps.app.f1234566-aaec-55a6-b123-bcb752069ec5", @@ -204,4 +201,4 @@ } }, "additionalProperties": true -} \ No newline at end of file +} diff --git a/schemas/notifications/ListingsItemIssuesChangeNotification.json b/schemas/notifications/ListingsItemIssuesChangeNotification.json index 957aa814..7e465caf 100644 --- a/schemas/notifications/ListingsItemIssuesChangeNotification.json +++ b/schemas/notifications/ListingsItemIssuesChangeNotification.json @@ -242,4 +242,4 @@ } } } -} +} \ No newline at end of file diff --git a/schemas/notifications/MfnOrderStatusChangeNotification.json b/schemas/notifications/MfnOrderStatusChangeNotification.json index ee4ff92a..565cd527 100644 --- a/schemas/notifications/MfnOrderStatusChangeNotification.json +++ b/schemas/notifications/MfnOrderStatusChangeNotification.json @@ -4,7 +4,6 @@ "type": "object", "title": "The root schema", "description": "The root schema comprises the entire JSON document.", - "default": {}, "examples": [ { "NotificationVersion": "1.0", @@ -87,7 +86,6 @@ "type": "object", "title": "The Payload schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "MFNOrderStatusChangeNotification": { @@ -113,7 +111,6 @@ "type": "object", "title": "The MFNOrderStatusChangeNotification schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "SellerId": "AXXXXXXXXXXXXX", @@ -251,7 +248,6 @@ "type": "object", "title": "The NotificationMetadata schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ApplicationId": "app-id-d0e9e693-c3ad-4373-979f-ed4ec98dd746", diff --git a/schemas/notifications/OrderStatusChangeNotification.json b/schemas/notifications/OrderStatusChangeNotification.json index 680cfdf5..cc35410f 100644 --- a/schemas/notifications/OrderStatusChangeNotification.json +++ b/schemas/notifications/OrderStatusChangeNotification.json @@ -4,7 +4,6 @@ "type": "object", "title": "The root schema", "description": "The root schema comprises the entire JSON document.", - "default": {}, "examples": [ { "NotificationVersion": "1.0", @@ -88,7 +87,6 @@ "type": "object", "title": "The Payload schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "OrderStatusChangeNotification": { @@ -115,7 +113,6 @@ "type": "object", "title": "The OrderStatusChangeNotification schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "SellerId": "AXXXXXXXXXXXXX", @@ -264,7 +261,6 @@ "type": "object", "title": "The NotificationMetadata schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ApplicationId": "app-id-d0e9e693-c3ad-4373-979f-ed4ec98dd746", @@ -325,4 +321,4 @@ } }, "additionalProperties": true -} \ No newline at end of file +} diff --git a/schemas/notifications/ProductTypeDefinitionsChangeNotification.json b/schemas/notifications/ProductTypeDefinitionsChangeNotification.json index a1317387..de82be5e 100644 --- a/schemas/notifications/ProductTypeDefinitionsChangeNotification.json +++ b/schemas/notifications/ProductTypeDefinitionsChangeNotification.json @@ -4,7 +4,6 @@ "type": "object", "title": "The root schema", "description": "The root schema comprises the entire JSON document.", - "default": {}, "examples": [ { "NotificationVersion":"1.0", @@ -82,7 +81,6 @@ "type": "object", "title": "The Payload schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "AccountId": "AXXXXXXXXXXX", @@ -154,7 +152,6 @@ "type": "object", "title": "The NotificationMetadata schema", "description": "An explanation about the purpose of this instance.", - "default": {}, "examples": [ { "ApplicationId": "amzn1.sellerapps.app.f1234566-aaec-55a6-b123-bcb752069ec5", @@ -215,4 +212,4 @@ } }, "additionalProperties": true -} \ No newline at end of file +}