├── .github └── PULL_REQUEST_TEMPLATE.md ├── CHANGES.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── package-lock.json ├── package.json ├── src ├── client.js ├── clientHelper.js └── constants.js └── tst ├── Readme.md ├── amazonPayClientTest.js ├── config.js ├── configWithAlgorithm.js ├── inStoreClientTest.js ├── unit └── clientHelperTest.js └── webStoreClientTest.js /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 7 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | ### Version 2.3.3 - May 2025 2 | * Introducing GetDispute API which is used to retrieve details of a chargeback dispute associated with a specific order 3 | * Introducing retry logic for HTTP Code 425 4 | 5 | ### Version 2.3.2 - February 2025 6 | * Introducing new v2 Dispute APIs for PSPs (Payment Service Provider). Buyers can create a dispute by filing an Amazon Pay A-to-z Guarantee claim or by filing a chargeback with their bank. 7 | * The `createDispute` API is used to notify Amazon of a newly created chargeback dispute by a buyer on a transaction processed by the PSP (Payment Service Provider), ensuring the dispute is properly accounted for in the Amazon Pay systems. 8 | * The `updateDispute` API is used to notify Amazon of the closure status of a chargeback dispute initiated by a buyer for orders processed by a partner PSP (Payment Service Provider), ensuring proper accounting within the Amazon systems. 9 | * The `contestDispute` API is used by the partner, on behalf of the merchant, to formally contest a dispute managed by Amazon, requiring the submission of necessary evidence files within the specified Dispute Window (11 days for Chargeback, 7 days for A-Z Claims). 10 | * The `uploadFile` API is utilised by PSPs (Payment Service Provider) to upload file-based evidence when a merchant contests a dispute, providing the necessary reference ID to the evidence file as part of the Update Dispute API process. 11 | * Introducing the `updateCharge` API which enables you to update the charge status of any PSP (Payment Service Provider) processed payment method (PPM) transactions. 12 | 13 | ### Version 2.3.1 - October 2023 14 | * Introducing new API called finalizeCheckoutSession which validates checkout attributes and finalizes checkout session. On success returns charge permission id and charge id. Use this API to process payments for JavaScript-based integrations. 15 | * Introducing new Merchant Onboarding & Account Management APIs, which allows our partners to onboard merchants programatically and as part of account management offer them creation, updation and deletion/dissociation capability. 16 | * Fixed the getReports API to handle null query parameters without throwing errors. 17 | * Added the Sample Code snippets for the Charge APIs, Charge Permission APIs and Refund APIs. 18 | * Updated the README file. 19 | 20 | ### Version 2.3.0 - March 2023 21 | * Introducing new v2 Reporting APIs. Reports allow you to retieve consolidated data about Amazon Pay transactions and settlements. In addition to managing and downloading reports using Seller Central, Amazon Pay offers APIs to manage and retrieve your reports. 22 | * Introducing new signature generation algorithm AMZN-PAY-RSASSA-PSS-V2 and increasing salt length from 20 to 32. 23 | * Added support for handling new parameter 'shippingAddressList' in Checkout Session response. Change is fully backwards compatible. 24 | * Added Error code 408 to API retry logic 25 | * Note : To use new algorithm AMZN-PAY-RSASSA-PSS-V2, "algorithm" needs to be provided as an additional field in "config" and also while rendering Amazon Pay button in "createCheckoutSessionConfig". The changes are backwards-compatible, SDK will use AMZN-PAY-RSASSA-PSS by default. 26 | 27 | #### Version 2.2.2 - June 2022 28 | * Fixed security vulnerabilities in dependencies. 29 | 30 | #### Version 2.2.1 - January 2022 31 | * Applied patch to address issues occurred in Version 2.2.0. 32 | **Please dont use Version 2.2.0** 33 | 34 | #### Version 2.2.0 - January 2022 35 | * Migrated signature generating algorithm from AMZN-PAY-RSASSA-PSS to AMZN-PAY-RSASSA-PSS-V2 & increased salt length from 20 to 32 36 | * Note : From this SDK version, "algorithm" need to be provided as additional field in "createCheckoutSessionConfig" while rendering Amazon Pay button. 37 | 38 | #### Version 2.1.5 - October 2021 39 | * Fixed Security Vulnerabilities by upgrading 'axios' library version 40 | * ReadMe file updates 41 | 42 | #### Version 2.1.4 - May 2021 43 | * Enabled support for environment specific keys (i.e Public key & Private key). The changes are fully backwards-compatible, where merchants can also use non environment specific keys 44 | 45 | #### Version 2.1.3 - April 2021 46 | * Removed deprecated library 'request' which is used to make HTTP/HTTPS calls 47 | * Added library 'axios' to make HTTP/HTTPS calls 48 | 49 | #### Version 2.1.2 - March 2021 50 | * Removing deprecated API calls 51 | 52 | #### Version 2.1.1 - June 2020 53 | * Underlying endpoint for getBuyer API changed 54 | 55 | #### Version 2.1.0 - June 2020 56 | * Added getBuyer() API call 57 | 58 | #### Version 2.0.1 - May 2020 59 | * Modify package.json to use @amazonpay scope for npm 60 | 61 | #### Version 2.0.0 - April 2020 62 | * Initial release 63 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Amazon Pay API SDK (NODE.JS) 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at http://aws.amazon.com/apache2.0 or in the "license" file accompanying this file. 7 | 8 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and limitations under the License. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Amazon Pay API SDK (Node.js) 2 | Amazon Pay Checkout v2 Integration 3 | 4 | Please note the Amazon Pay API SDK can only be used for API calls to the pay-api.amazon.com|eu|jp endpoint. 5 | 6 | ## Requirements 7 | 8 | * Amazon Pay account: To register for Amazon Pay, go to https://pay.amazon.com, choose your region by selecting the flag icon in the upper right corner, and then click "Register". 9 | * Node 8.0 or higher 10 | 11 | ## Install 12 | 13 | To use this module directly, install it as a dependency: 14 | 15 | ``` 16 | npm i @amazonpay/amazon-pay-api-sdk-nodejs 17 | ``` 18 | 19 | ## Public and Private Keys 20 | 21 | MWS access keys, MWS secret keys, and MWS authorization tokens from previous MWS integrations cannot be used with this SDK. 22 | 23 | You will need to generate your own public/private key pair to make API calls with this SDK. 24 | 25 | In Windows 10 this can be done with ssh-keygen commands: 26 | 27 | ``` 28 | ssh-keygen -t rsa -b 2048 -f private.pem 29 | ssh-keygen -f private.pem -e -m PKCS8 > public.pub 30 | ``` 31 | 32 | In Linux or macOS this can be done using openssl commands: 33 | 34 | ``` 35 | openssl genrsa -out private.pem 2048 36 | openssl rsa -in private.pem -pubout > public.pub 37 | ``` 38 | 39 | The first command above generates a private key and the second line uses the private key to generate a public key. 40 | 41 | To associate the key with your account, follow the instructions here to 42 | [Get your Public Key ID](https://developer.amazon.com/docs/amazon-pay-checkout/get-set-up-for-integration.html#5-get-your-public-key-id). 43 | 44 | ## Configuration 45 | 46 | ``` js 47 | const fs = require('fs'); 48 | const config = { 49 | 'publicKeyId': 'ABC123DEF456XYZ', // RSA Public Key ID (this is not the Merchant or Seller ID) 50 | 'privateKey': fs.readFileSync('tst/private.pem'), // Path to RSA Private Key (or a string representation) 51 | 'region': 'us', // Must be one of: 'us', 'eu', 'jp' 52 | 'sandbox': true, // true (Sandbox) or false (Production) boolean 53 | 'algorithm': 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 54 | }; 55 | ``` 56 | 57 | If you have created environment specific keys (i.e Public Key Starts with LIVE or SANDBOX) in Seller Central, then use those PublicKeyId & PrivateKey. In this case, there is no need to pass the Sandbox parameter to the ApiConfiguration. 58 | 59 | ``` js 60 | const fs = require('fs'); 61 | const config = { 62 | 'publicKeyId': 'PUBLIC_KEY_ID', // LIVE-XXXXX or SANDBOX-XXXXX 63 | 'privateKey': fs.readFileSync('tst/private.pem'), // Path to RSA Private Key (or a string representation) 64 | 'region': 'us', // Must be one of: 'us', 'eu', 'jp' 65 | 'algorithm': 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 66 | }; 67 | ``` 68 | 69 | # Versioning 70 | The pay-api.amazon.com|eu|jp endpoint uses versioning to allow future updates. The major version of this SDK will stay aligned with the API version of the endpoint. 71 | 72 | If you have downloaded version 2.x.y of this SDK, version in below examples would be "v2". 73 | 74 | # Convenience Functions (Overview) 75 | 76 | Make use of the built-in convenience functions to easily make API calls. Scroll down further to see example code snippets. 77 | 78 | When using the convenience functions, the request payload will be signed using the provided private key, and a HTTPS request is made to the correct regional endpoint. 79 | In the event of request throttling, the HTTPS call will be attempted up to three times 80 | 81 | ## Alexa Delivery Trackers API 82 | Please note that your merchant account must be whitelisted to use the [Delivery Trackers API](https://developer.amazon.com/docs/amazon-pay-onetime/delivery-order-notifications.html). 83 | 84 | * **deliveryTrackers**(payload, headers = null) → POST to `${version}/deliveryTrackers` 85 | 86 | ## Authorization Tokens API 87 | Please note that your solution provider account must have a pre-existing relationship (valid and active MWS authorization token) with the merchant account in order to use this function. 88 | 89 | * **getAuthorizationToken**(mwsAuthToken, merchantId, headers = null) → GET to `${version}/authorizationTokens/${mwsAuthToken}?merchantId=${merchantId}` 90 | 91 | ## Amazon Checkout v2 API 92 | [Checkout v2 Integration Guide](https://developer.amazon.com/docs/amazon-pay-api-v2/introduction.html) 93 | 94 | The headers field is not optional for create/POST calls below because it requires, at a minimum, the x-amz-pay-idempotency-key header: 95 | 96 | ``` js 97 | const headers = { 98 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 99 | }; 100 | ``` 101 | 102 | ### Amazon Checkout v2 Buyer APIs 103 | * **getBuyer**($buyerToken, $headers = null) → GET to `${version}/buyer/{$buyerToken}` 104 | 105 | ### Checkout v2 CheckoutSession APIs 106 | * **createCheckoutSession**(payload, headers) → POST to `${version}/checkoutSessions` 107 | * **getCheckoutSession**(checkoutSessionId, headers = null) → GET to `${version}/checkoutSessions/${checkoutSessionId}` 108 | * **updateCheckoutSession**(checkoutSessionId, payload, headers = null) → PATCH to `${version}/checkoutSessions/${checkoutSessionId}` 109 | * **completeCheckoutSession**(checkoutSessionId, payload, headers = null) → POST to `${version}/checkoutSessions/${checkoutSessionId}/complete` 110 | 111 | ### Checkout v2 ChargePermission APIs 112 | * **getChargePermission**(chargePermissionId, headers = null) → GET to `${version}/chargePermissions/${chargePermissionId}` 113 | * **updateChargePermission**(chargePermissionId, payload, headers = null) → PATCH to `${version}/chargePermissions/${chargePermissionId}` 114 | * **closeChargePermission**(chargePermissionId, payload, headers = null) → DELETE to `${version}/chargePermissions/${chargePermissionId}/close` 115 | 116 | ### Checkout v2 Charge APIs 117 | * **createCharge**(payload, headers) → POST to `${version}/charges` 118 | * **getCharge**(chargeId, headers = null) → GET to `${version}/charges/${chargeId}` 119 | * **updateCharge** (chargeId, payload, headers = null) → PATCH `${version}/charges/${chargeId}` 120 | * **captureCharge**(chargeId, payload, headers) → POST to `${version}/charges/${chargeId}/capture` 121 | * **cancelCharge**(chargeId, payload, headers = null) → DELETE to `${version}/charges/${chargeId}/cancel` 122 | 123 | ### Checkout v2 Refund APIs 124 | * **createRefund**(payload, headers) → POST to `${version}/refunds` 125 | * **getRefund**(refundId, headers = null) → GET to `${version}/refunds/${refundId}` 126 | 127 | ## In-Store API 128 | Please contact your Amazon Pay Account Manager before using the In-Store API calls in a Production environment to obtain a copy of the In-Store Integration Guide. 129 | 130 | * **instoreMerchantScan**(payload, headers = null) → POST to `${version}/in-store/merchantScan` 131 | * **instoreCharge**(payload, headers = null) → POST to `${version}/in-store/charge` 132 | * **instoreRefund**(payload, headers = null) → POST to `${version}/in-store/refund` 133 | 134 | ### Amazon Checkout v2 SPC 135 | * **finalizeCheckoutSession**(checkoutSessionId, payload, headers = null) → POST to `${version}/checkoutSessions/${checkoutSessionId}/finalize` 136 | 137 | ### Amazon Checkout v2 Merchant Onboarding & Account Management APIs 138 | * **registerAmazonPayAccount**(payload, headers = null) → POST to `${version}/merchantAccounts` 139 | * **updateAmazonPayAccount**(merchantAccountId, payload, headers = null) → PATCH to `${version}/merchantAccounts/${merchantAccountId}` 140 | * **deleteAmazonPayAccount**(merchantAccountId, headers = null) → DELETE to `${version}/merchantAccounts/${merchantAccountId}` 141 | 142 | ### Amazon Checkout v2 Dispute APIs 143 | 144 | * **createDispute**(payload,headers) → POST to `${version}/disputes` 145 | * **getDispute**(disputeId,headers= null) → GET to `${version}/disputes/${disputeId}` 146 | * **updateDispute**(disputeId,payload,headers = null) → PATCH to `${version}/disputes/${disputeId}` 147 | * **contestDispute**(disputeId, payload, headers= null) → POST to `${version}/disputes/${disputeId}/contest` 148 | 149 | ### Amazon Checkout v2 File APIs 150 | * **uploadFile**($payload,headers) → POST to `${version}/files` 151 | 152 | # Using Convenience Functions 153 | 154 | Four quick steps are needed to make an API call: 155 | 156 | Step 1. Construct a Client (using the previously defined Config object). 157 | 158 | ``` js 159 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 160 | 161 | const testPayClient = new Client.AmazonPayClient(config); 162 | // -or- 163 | const testPayClient = new Client.WebStoreClient(config); 164 | // -or- 165 | const testPayClient = new Client.InStoreClient(config); 166 | ``` 167 | 168 | Step 2. Generate the payload. 169 | 170 | ``` js 171 | const payload = { 172 | scanData: 'UKhrmatMeKdlfY6b', 173 | scanReferenceId: uuidv4().toString().replace(/-/g, ''), 174 | merchantCOE: 'US', 175 | ledgerCurrency: 'USD', 176 | chargeTotal: { 177 | currencyCode: 'USD', 178 | amount: '2.00' 179 | }, 180 | storeLocation: { 181 | countryCode: 'US' 182 | }, 183 | metadata: { 184 | merchantNote: 'Merchant Name', 185 | customInformation: 'in-store Software Purchase', 186 | communicationContext: { 187 | merchantStoreName: 'Store Name', 188 | merchantOrderId: '789123' 189 | } 190 | } 191 | }; 192 | ``` 193 | 194 | Step 3. Execute the call. 195 | 196 | ``` js 197 | const response = testPayClient.merchantScan(payload); 198 | ``` 199 | 200 | If you are a Solution Provider and need to make an API call on behalf of a different merchant account, you will need to pass along an extra authentication token parameter into the API call. 201 | ``` js 202 | const testHeaders = { 203 | 'x-amz-pay-authtoken': 'other_merchant_super_secret_token' 204 | }; 205 | const response = testpayClient.merchantScan(payload, testHeaders); 206 | ``` 207 | 208 | # Convenience Functions Code Samples 209 | 210 | ## Alexa Delivery Notifications 211 | 212 | ``` js 213 | const fs = require('fs'); 214 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 215 | 216 | const config = { 217 | publicKeyId: 'ABC123DEF456XYZ', 218 | privateKey: fs.readFileSync('tst/private.pem'), 219 | region: 'us', 220 | sandbox: true, 221 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 222 | }; 223 | 224 | const payload = { 225 | amazonOrderReferenceId: 'P00-0000000-0000000', 226 | deliveryDetails: [{ 227 | trackingNumber: '1Z999AA10123456789', 228 | carrierCode: 'UPS' 229 | }] 230 | }; 231 | 232 | const testPayClient = new Client.AmazonPayClient(config); 233 | testPayClient.deliveryTrackers(payload).then((apiResponse) => { 234 | const response = apiResponse; 235 | }); 236 | ``` 237 | 238 | ## Checkout v2 - Create Checkout Session 239 | 240 | ``` js 241 | const fs = require('fs'); 242 | const uuidv4 = require('uuid/v4'); 243 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 244 | 245 | const config = { 246 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 247 | privateKey: fs.readFileSync('tst/private.pem'), 248 | region: 'YOUR_REGION_CODE', 249 | sandbox: true, 250 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 251 | }; 252 | 253 | const payload = { 254 | webCheckoutDetails: { 255 | checkoutReviewReturnUrl: 'https://localhost/store/checkoutReview', 256 | checkoutResultReturnUrl: 'https://localhost/store/checkoutReturn' 257 | }, 258 | storeId: 'amzn1.application-oa2-client.5cc4962582fd4025a2962fc5350582d9' // Enter Client ID 259 | }; 260 | const headers = { 261 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 262 | }; 263 | 264 | const testPayClient = new Client.WebStoreClient(config); 265 | const response = testPayClient.createCheckoutSession(payload, headers); 266 | 267 | response.then(function (result) { 268 | console.log(result.data); 269 | }).catch(err => { 270 | console.log(err); 271 | }); 272 | ``` 273 | 274 | ## Checkout v2 - Get Checkout Session 275 | 276 | ``` js 277 | const fs = require('fs'); 278 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 279 | 280 | const config = { 281 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 282 | privateKey: fs.readFileSync('tst/private.pem'), 283 | region: 'YOUR_REGION_CODE', 284 | sandbox: true, 285 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 286 | }; 287 | 288 | const checkoutSessionId = "00000000-0000-0000-0000-000000000000"; 289 | const testPayClient = new Client.WebStoreClient(config); 290 | const response = testPayClient.getCheckoutSession(checkoutSessionId); 291 | 292 | response.then(function (result) { 293 | console.log(result.data); 294 | }).catch(err => { 295 | console.log(err); 296 | }); 297 | ``` 298 | 299 | ## Checkout v2 - Update Checkout Session 300 | 301 | ``` js 302 | const fs = require('fs'); 303 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 304 | 305 | const config = { 306 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 307 | privateKey: fs.readFileSync('tst/private.pem'), 308 | region: 'YOUR_REGION_CODE', 309 | sandbox: true, 310 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 311 | }; 312 | 313 | const payload = { 314 | webCheckoutDetails: { 315 | checkoutResultReturnUrl: 'https://localhost/store/checkoutReturn' 316 | }, 317 | paymentDetails: { 318 | paymentIntent: 'Confirm', 319 | canHandlePendingAuthorization: false, 320 | chargeAmount: { 321 | amount: 50, 322 | currencyCode: 'USD' 323 | } 324 | }, 325 | merchantMetadata: { 326 | merchantReferenceId: uuidv4().toString().replace(/-/g, ''), 327 | merchantStoreName: 'AmazonTestStoreFront', 328 | noteToBuyer: 'merchantNoteForBuyer', 329 | customInformation: '' 330 | } 331 | }; 332 | 333 | const checkoutSessionId = "00000000-0000-0000-0000-000000000000"; 334 | const testPayClient = new Client.WebStoreClient(config); 335 | const response = testPayClient.updateCheckoutSession(checkoutSessionId, payload); 336 | 337 | response.then(function (result) { 338 | console.log(result.data); 339 | }).catch(err => { 340 | console.log(err); 341 | }); 342 | ``` 343 | 344 | ## Checkout v2 - Complete Checkout Session 345 | 346 | ``` js 347 | const fs = require('fs'); 348 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 349 | 350 | const config = { 351 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 352 | privateKey: fs.readFileSync('tst/private.pem'), 353 | region: 'YOUR_REGION_CODE', 354 | sandbox: true, 355 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 356 | }; 357 | 358 | const payload = { 359 | "chargeAmount": { 360 | "amount": "1.23", 361 | "currencyCode": "USD" 362 | } 363 | }; 364 | 365 | const checkoutSessionId = "00000000-0000-0000-0000-000000000000"; 366 | const testPayClient = new Client.WebStoreClient(config); 367 | const response = testPayClient.completeCheckoutSession(checkoutSessionId, payload); 368 | 369 | response.then(function (result) { 370 | console.log(result.data); 371 | }).catch(err => { 372 | console.log(err); 373 | }); 374 | ``` 375 | 376 | 377 | ## Checkout v2 - Get Charge Permission API 378 | ```js 379 | const fs = require('fs'); 380 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 381 | 382 | const config = { 383 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 384 | privateKey: fs.readFileSync('tst/private.pem'), 385 | region: 'YOUR_REGION_CODE', 386 | sandbox: true, 387 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 388 | }; 389 | 390 | const chargePermissionId = "S01-0000000-0000000"; 391 | const testPayClient = new Client.WebStoreClient(config); 392 | const response = testPayClient.getChargePermission(chargePermissionId); 393 | 394 | response.then(function (result) { 395 | console.log(result.data); 396 | }).catch(err => { 397 | console.log(err); 398 | }); 399 | ``` 400 | 401 | ## Checkout v2 - Update Charge Permission API 402 | ```js 403 | const fs = require('fs'); 404 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 405 | 406 | const config = { 407 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 408 | privateKey: fs.readFileSync('tst/private.pem'), 409 | region: 'YOUR_REGION_CODE', 410 | sandbox: true, 411 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 412 | }; 413 | 414 | const chargePermissionId = "S01-0000000-0000000"; 415 | const payload = { 416 | merchantMetadata: { 417 | merchantReferenceId: "32-41-323141-32", 418 | merchantStoreName: "AmazonTestStoreFront", 419 | noteToBuyer: "Some Note to buyer", 420 | customInformation: "" 421 | } 422 | }; 423 | 424 | const testPayClient = new Client.WebStoreClient(config); 425 | const response = testPayClient.updateChargePermission(chargePermissionId, payload); 426 | 427 | response.then(function (result) { 428 | console.log(result.data); 429 | }).catch(err => { 430 | console.log(err); 431 | }); 432 | ``` 433 | 434 | ## Checkout v2 - Close Charge Permission API 435 | ```js 436 | const fs = require('fs'); 437 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 438 | 439 | const config = { 440 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 441 | privateKey: fs.readFileSync('tst/private.pem'), 442 | region: 'YOUR_REGION_CODE', 443 | sandbox: true, 444 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 445 | }; 446 | 447 | const chargePermissionId = "S01-0000000-0000000"; 448 | const payload = { 449 | closureReason: "No more charges required", 450 | cancelPendingCharges: false 451 | }; 452 | 453 | const testPayClient = new Client.WebStoreClient(config); 454 | const response = testPayClient.closeChargePermission(chargePermissionId, payload); 455 | 456 | response.then(function (result) { 457 | console.log(result.data); 458 | }).catch(err => { 459 | console.log(err); 460 | }); 461 | ``` 462 | 463 | ## Checkout v2 - Create Charge API 464 | ```js 465 | const fs = require('fs'); 466 | const uuidv4 = require('uuid/v4'); 467 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 468 | 469 | const config = { 470 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 471 | privateKey: fs.readFileSync('tst/private.pem'), 472 | region: 'YOUR_REGION_CODE', 473 | sandbox: true, 474 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 475 | }; 476 | 477 | const payload = { 478 | chargePermissionId: "S01-0000000-0000000", 479 | chargeAmount: { 480 | amount: "14.00", 481 | currencyCode: "USD" 482 | }, 483 | captureNow: true, 484 | softDescriptor: "Descriptor", 485 | canHandlePendingAuthorization: false 486 | }; 487 | 488 | const headers = { 489 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 490 | }; 491 | 492 | const testPayClient = new Client.WebStoreClient(config); 493 | const response = testPayClient.createCharge(payload, headers); 494 | 495 | response.then(function (result) { 496 | console.log(result.data); 497 | }).catch(err => { 498 | console.log(err); 499 | }); 500 | ``` 501 | 502 | ## Checkout v2 - Get Charge API 503 | ```js 504 | const fs = require('fs'); 505 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 506 | 507 | const config = { 508 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 509 | privateKey: fs.readFileSync('tst/private.pem'), 510 | region: 'YOUR_REGION_CODE', 511 | sandbox: true, 512 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 513 | }; 514 | 515 | const chargeId = "S01-0000000-0000000-C000000"; 516 | 517 | const testPayClient = new Client.WebStoreClient(config); 518 | const response = testPayClient.getCharge(chargeId); 519 | 520 | response.then(function (result) { 521 | console.log(result.data); 522 | }).catch(err => { 523 | console.log(err); 524 | }); 525 | ``` 526 | 527 | ## Amazon Checkout v2 - Update Charge API 528 | **Please note that is API is supported only for PSPs (Payment Service Provider)** 529 | 530 | ```js 531 | const fs = require('fs'); 532 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 533 | 534 | const config = { 535 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 536 | privateKey: fs.readFileSync('tst/private.pem'), 537 | region: 'YOUR_REGION_CODE', 538 | sandbox: true, 539 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 540 | }; 541 | 542 | const payload = { 543 | "statusDetails": { 544 | "state": "Canceled", 545 | "reasonCode": "ExpiredUnused" 546 | } 547 | }; 548 | 549 | const chargeId = "S01-0000000-0000000-C000000"; 550 | 551 | const testPayClient = new Client.WebStoreClient(config); 552 | const response = testPayClient.updateCharge(chargeId, payload); 553 | 554 | response.then(function (result) { 555 | console.log(result.data); 556 | }).catch(err => { 557 | console.log(err); 558 | }); 559 | ``` 560 | 561 | ## Checkout v2 - Capture Charge API 562 | 563 | ``` js 564 | const fs = require('fs'); 565 | const uuidv4 = require('uuid/v4'); 566 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 567 | 568 | const config = { 569 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 570 | privateKey: fs.readFileSync('tst/private.pem'), 571 | region: 'YOUR_REGION_CODE', 572 | sandbox: true, 573 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 574 | }; 575 | 576 | const payload = { 577 | captureAmount: { 578 | amount: '10.00', 579 | currencyCode: 'USD' 580 | }, 581 | softDescriptor: 'AMZN' 582 | }; 583 | 584 | const headers = { 585 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 586 | }; 587 | 588 | const chargeId = 'S01-0000000-0000000-C000000'; 589 | const testPayClient = new Client.WebStoreClient(config); 590 | const response = testPayClient.captureCharge(chargeId, payload, headers); 591 | 592 | response.then(function (result) { 593 | console.log(result.data); 594 | }).catch(err => { 595 | console.log(err); 596 | }); 597 | ``` 598 | 599 | ## Checkout v2 - Cancel Charge API 600 | 601 | ``` js 602 | const fs = require('fs'); 603 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 604 | 605 | const config = { 606 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 607 | privateKey: fs.readFileSync('tst/private.pem'), 608 | region: 'YOUR_REGION_CODE', 609 | sandbox: true, 610 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 611 | }; 612 | 613 | const payload = { 614 | cancellationReason: 'REASON DESCRIPTION' 615 | }; 616 | 617 | const chargeId = 'S01-0000000-0000000-C000000'; 618 | const testPayClient = new Client.WebStoreClient(config); 619 | const response = testPayClient.cancelCharge(chargeId, payload); 620 | 621 | response.then(function (result) { 622 | console.log(result.data); 623 | }).catch(err => { 624 | console.log(err); 625 | }); 626 | ``` 627 | 628 | ## Checkout v2 - Create Refund API 629 | 630 | ``` js 631 | const fs = require('fs'); 632 | const uuidv4 = require('uuid/v4'); 633 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 634 | 635 | const config = { 636 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 637 | privateKey: fs.readFileSync('tst/private.pem'), 638 | region: 'YOUR_REGION_CODE', 639 | sandbox: true, 640 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 641 | }; 642 | 643 | const payload = { 644 | chargeId: 'S01-0000000-0000000-C000000', 645 | refundAmount: { 646 | amount: '14.00', 647 | currencyCode: 'USD' 648 | }, 649 | softDescriptor: 'Descriptor' 650 | }; 651 | 652 | const headers = { 653 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 654 | }; 655 | 656 | const testPayClient = new Client.WebStoreClient(config); 657 | const response = testPayClient.createRefund(payload, headers); 658 | 659 | response.then(function (result) { 660 | console.log(result.data); 661 | }).catch(err => { 662 | console.log(err); 663 | }); 664 | ``` 665 | 666 | ## Checkout v2 - Get Refund API 667 | 668 | ``` js 669 | const fs = require('fs'); 670 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 671 | 672 | const config = { 673 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 674 | privateKey: fs.readFileSync('tst/private.pem'), 675 | region: 'YOUR_REGION_CODE', 676 | sandbox: true, 677 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 678 | }; 679 | 680 | const refundId = "S01-0000000-0000000-R000000"; 681 | 682 | const testPayClient = new Client.WebStoreClient(config); 683 | const response = testPayClient.getRefund(refundId); 684 | 685 | response.then(function (result) { 686 | console.log(result.data); 687 | }).catch(err => { 688 | console.log(err); 689 | }); 690 | ``` 691 | 692 | ## In Store MerchantScan 693 | 694 | ``` js 695 | const payload = { 696 | scanData: '[scanData]', 697 | scanReferenceId: '[scanReferenceId]', 698 | merchantCOE: 'US', 699 | ledgerCurrency: 'USD' 700 | }; 701 | 702 | testInStoreClient.merchantScan(payload).then(function (response) { 703 | const merchantScanChargePermissionId = response.data.chargePermissionId; 704 | }); 705 | ``` 706 | 707 | ## Generate Button Signature 708 | The signatures generated by this helper function are only valid for the Checkout v2 front-end buttons. Unlike API signing, no timestamps are involved, so the result of this function can be considered a static signature that can safely be placed in your website JS source files and used repeatedly (as long as your payload does not change). 709 | 710 | Example call to generateButtonSignature function: 711 | 712 | ``` js 713 | const fs = require('fs'); 714 | const uuidv4 = require('uuid/v4'); 715 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 716 | 717 | const config = { 718 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 719 | privateKey: fs.readFileSync('tst/private.pem'), 720 | region: 'YOUR_REGION_CODE', 721 | sandbox: true, 722 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 723 | }; 724 | 725 | const testPayClient = new Client.AmazonPayClient(config); 726 | const payload = { 727 | webCheckoutDetails: { 728 | checkoutReviewReturnUrl: 'https://localhost/test/checkoutReview.html', 729 | checkoutResultReturnUrl: 'https://localhost/test/checkoutResult.html' 730 | }, 731 | storeId: 'amzn1.application-oa2-client.xxxxx' 732 | }; 733 | const signature = testPayClient.generateButtonSignature(payload); 734 | ``` 735 | 736 | ## Manual Signing (Advanced Use-Cases Only) 737 | This SDK provides the ability to help you manually sign your API requests if you want to use your own code for sending the HTTPS request over the Internet. 738 | 739 | Example call to apiCall function with values: 740 | 741 | ``` js 742 | /** API to process a request 743 | * - Makes an API Call using the specified options. 744 | * @param {Object} options - The options to make the API Call 745 | * @param {String} options.method - The HTTP request method 746 | * @param {String} options.urlFragment - The URI for the API Call 747 | * @param {String} [options.payload=null] - The payload for the API Call 748 | * @param {String} [options.headers=null] - The headers for the API Call 749 | ``` 750 | 751 | Example request method: 752 | ``` js 753 | const options = { 754 | method: 'POST', 755 | urlFragment: '${version}/in-store/merchantScan', 756 | payload: { 757 | scanData: 'UKhrmatMeKdlfY6b', 758 | scanReferenceId: '0b8fb271-2ae2-49a5-b35d4', 759 | merchantCOE: 'US', 760 | ledgerCurrency: 'USD', 761 | chargeTotal: { 762 | currencyCode: 'USD', 763 | amount: '2.00' 764 | }, 765 | storeLocation: { 766 | countryCode: 'US' 767 | }, 768 | metadata: { 769 | merchantNote: 'Merchant Name', 770 | customInformation: 'in-store Software Purchase', 771 | communicationContext: { 772 | merchantStoreName: 'Store Name', 773 | merchantOrderId: '789123' 774 | } 775 | } 776 | } 777 | }; 778 | 779 | const client = new Client.InStoreClient(config); 780 | client.apiCall(options).then((apiResponse) => { 781 | const signedHeders = apiResponse; 782 | }); 783 | ``` 784 | 785 | Example call to getSignedHeaders function with values: 786 | (This will only be used if you don't use apiCall and want to create your own custom headers.) 787 | 788 | ``` js 789 | /** Signs the request headers 790 | * - Signs the request provided and returns the signed headers object. 791 | * @param {Object} options - The options to make the API Call 792 | * @param {String} options.method - The HTTP request method 793 | * @param {String} options.urlFragment - The URI for the API Call 794 | * @param {String} [options.payload=null] - The payload for the API Call 795 | * @param {String} [options.headers=null] - The headers for the API Call 796 | **/ 797 | ``` 798 | 799 | Example request method: 800 | ``` js 801 | const options = { 802 | method: 'POST', 803 | urlFragment: '${version}/in-store/merchantScan', 804 | payload: { 805 | scanData: 'UKhrmatMeKdlfY6b', 806 | scanReferenceId: '0b8fb271-2ae2-49a5-b35d4', 807 | merchantCOE: 'US', 808 | ledgerCurrency: 'USD', 809 | chargeTotal: { 810 | currencyCode: 'USD', 811 | amount: '2.00' 812 | }, 813 | storeLocation: { 814 | countryCode: 'US' 815 | }, 816 | metadata: { 817 | merchantNote: 'Merchant Name', 818 | customInformation: 'in-store Software Purchase', 819 | communicationContext: { 820 | merchantStoreName: 'Store Name', 821 | merchantOrderId: '789123' 822 | } 823 | } 824 | }, 825 | headers: { 826 | 'Accept': 'application/json', 827 | 'Content-Type': 'application/json' 828 | 'X-Amz-Pay-Region': 'us' 829 | } 830 | }; 831 | 832 | const client = new Client.AmazonPayClient(config); 833 | const signedHeaders = client.getSignedHeaders(options); 834 | ``` 835 | 836 | # Reporting APIs code samples 837 | 838 | ## Amazon Checkout v2 Reporting APIs - GetReport API 839 | ```js 840 | const fs = require('fs'); 841 | const uuidv4 = require('uuid/v4'); 842 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 843 | 844 | const config = { 845 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 846 | privateKey: fs.readFileSync('tst/private.pem'), 847 | region: 'YOUR_REGION_CODE', 848 | sandbox: false, 849 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 850 | }; 851 | 852 | const testPayClient = new Client.WebStoreClient(config); 853 | const requestPayload = { 854 | reportTypes: "_GET_FLAT_FILE_OFFAMAZONPAYMENTS_SETTLEMENT_DATA_", 855 | }; 856 | const response = testPayClient.getReports(requestPayload); 857 | 858 | response.then(function (result) { 859 | console.log(result.data); 860 | }).catch(err => { 861 | console.log(err); 862 | }); 863 | ``` 864 | 865 | ## Amazon Checkout v2 Reporting APIs - GetReportById API 866 | ```js 867 | const fs = require('fs'); 868 | const uuidv4 = require('uuid/v4'); 869 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 870 | 871 | const config = { 872 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 873 | privateKey: fs.readFileSync('tst/private.pem'), 874 | region: 'YOUR_REGION_CODE', 875 | sandbox: false, 876 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 877 | }; 878 | 879 | const reportId = '1234567890'; 880 | const testPayClient = new Client.WebStoreClient(config); 881 | const response = testPayClient.getReportById(reportId); 882 | 883 | response.then(function (result) { 884 | console.log(result.data); 885 | }).catch(err => { 886 | console.log(err); 887 | }); 888 | ``` 889 | 890 | ## Amazon Checkout v2 Reporting APIs - GetReportDocument API 891 | ```js 892 | const fs = require('fs'); 893 | const uuidv4 = require('uuid/v4'); 894 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 895 | 896 | const config = { 897 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 898 | privateKey: fs.readFileSync('tst/private.pem'), 899 | region: 'YOUR_REGION_CODE', 900 | sandbox: false, 901 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 902 | }; 903 | 904 | const reportDocumentId = 'amzn1.tortuga.0.000000000-0000-0000-0000-000000000000.00000000000000'; 905 | const testPayClient = new Client.WebStoreClient(config); 906 | const response = testPayClient.getReportDocument(reportDocumentId); 907 | 908 | response.then(function (result) { 909 | console.log(result.data); 910 | }).catch(err => { 911 | console.log(err); 912 | }); 913 | ``` 914 | 915 | ## Amazon Checkout v2 Reporting APIs - GetReportSchedules API 916 | ```js 917 | const fs = require('fs'); 918 | const uuidv4 = require('uuid/v4'); 919 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 920 | 921 | const config = { 922 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 923 | privateKey: fs.readFileSync('tst/private.pem'), 924 | region: 'YOUR_REGION_CODE', 925 | sandbox: false, 926 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 927 | }; 928 | 929 | const reportTypes = '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_ORDER_REFERENCE_DATA_,_GET_FLAT_FILE_OFFAMAZONPAYMENTS_BILLING_AGREEMENT_DATA_'; 930 | const testPayClient = new Client.WebStoreClient(config); 931 | const response = testPayClient.getReportSchedules(reportTypes); 932 | 933 | response.then(function (result) { 934 | console.log(result.data); 935 | }).catch(err => { 936 | console.log(err); 937 | }); 938 | ``` 939 | 940 | ## Amazon Checkout v2 Reporting APIs - GetReportScheduleById API 941 | ```js 942 | const fs = require('fs'); 943 | const uuidv4 = require('uuid/v4'); 944 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 945 | 946 | const config = { 947 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 948 | privateKey: fs.readFileSync('tst/private.pem'), 949 | region: 'YOUR_REGION_CODE', 950 | sandbox: false, 951 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 952 | }; 953 | 954 | const reportScheduleId = '1234567890'; 955 | const testPayClient = new Client.WebStoreClient(config); 956 | const response = testPayClient.getReportScheduleById(reportScheduleId); 957 | 958 | response.then(function (result) { 959 | console.log(result.data); 960 | }).catch(err => { 961 | console.log(err); 962 | }); 963 | ``` 964 | 965 | ## Amazon Checkout v2 Reporting APIs - CreateReport API 966 | ```js 967 | const fs = require('fs'); 968 | const uuidv4 = require('uuid/v4'); 969 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 970 | 971 | const config = { 972 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 973 | privateKey: fs.readFileSync('tst/private.pem'), 974 | region: 'YOUR_REGION_CODE', 975 | sandbox: false, 976 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 977 | }; 978 | 979 | const requestPayload = { 980 | reportType: '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_AUTHORIZATION_DATA_', 981 | startTime: '20221114T074550Z', 982 | endTime: '20221114T074550Z' 983 | } 984 | const testPayClient = new Client.WebStoreClient(config); 985 | const response = testPayClient.createReport(requestPayload); 986 | 987 | response.then(function (result) { 988 | console.log(result.data); 989 | }).catch(err => { 990 | console.log(err); 991 | }); 992 | ``` 993 | 994 | ## Amazon Checkout v2 Reporting APIs - CreateReportSchedule API 995 | ```js 996 | const fs = require('fs'); 997 | const uuidv4 = require('uuid/v4'); 998 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 999 | 1000 | const config = { 1001 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 1002 | privateKey: fs.readFileSync('tst/private.pem'), 1003 | region: 'YOUR_REGION_CODE', 1004 | sandbox: false, 1005 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 1006 | }; 1007 | 1008 | const requestPayload = { 1009 | reportType: "_GET_FLAT_FILE_OFFAMAZONPAYMENTS_ORDER_REFERENCE_DATA_", 1010 | scheduleFrequency: "P1D", 1011 | nextReportCreationTime: "20230317T074550Z", 1012 | deleteExistingSchedule: false 1013 | } 1014 | const testPayClient = new Client.WebStoreClient(config); 1015 | const response = testPayClient.createReportSchedule(requestPayload); 1016 | 1017 | response.then(function (result) { 1018 | console.log(result.data); 1019 | }).catch(err => { 1020 | console.log(err); 1021 | }); 1022 | ``` 1023 | 1024 | ## Amazon Checkout v2 Reporting APIs - CancelReportSchedule API 1025 | ```js 1026 | const fs = require('fs'); 1027 | const uuidv4 = require('uuid/v4'); 1028 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 1029 | 1030 | const config = { 1031 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 1032 | privateKey: fs.readFileSync('tst/private.pem'), 1033 | region: 'YOUR_REGION_CODE', 1034 | sandbox: false, 1035 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 1036 | }; 1037 | 1038 | const reportScheduleId = "1234567890"; 1039 | const testPayClient = new Client.WebStoreClient(config); 1040 | const response = testPayClient.cancelReportSchedule(reportScheduleId); 1041 | 1042 | response.then(function (result) { 1043 | console.log(result.data); 1044 | }).catch(err => { 1045 | console.log(err); 1046 | }); 1047 | ``` 1048 | 1049 | ## Amazon Checkout v2 SPC - Finalize Checkout Session API 1050 | ```js 1051 | const fs = require('fs'); 1052 | const uuidv4 = require('uuid/v4'); 1053 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 1054 | 1055 | const config = { 1056 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 1057 | privateKey: fs.readFileSync('tst/private.pem'), 1058 | region: 'YOUR_REGION_CODE', 1059 | sandbox: true, 1060 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 1061 | }; 1062 | 1063 | const checkoutSessionId = "00000000-0000-0000-0000-000000000000"; 1064 | const payload = { 1065 | shippingAddress: { 1066 | name: "Susie Smith", 1067 | addressLine1: "10 Ditka Ave", 1068 | addressLine2: "Suite 2500", 1069 | city: "Chicago", 1070 | county: null, 1071 | district: null, 1072 | stateOrRegion: "IL", 1073 | postalCode: "60602", 1074 | countryCode: "US", 1075 | phoneNumber: "800-000-0000" 1076 | }, 1077 | billingAddress: null, 1078 | chargeAmount: { 1079 | amount: 10, 1080 | currencyCode: "USD" 1081 | }, 1082 | totalOrderAmount: { 1083 | amount: 10, 1084 | currencyCode: "USD" 1085 | }, 1086 | paymentIntent: "Confirm", 1087 | canHandlePendingAuthorization: false 1088 | }; 1089 | const headers = { 1090 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 1091 | }; 1092 | 1093 | const testPayClient = new Client.WebStoreClient(config); 1094 | const response = testPayClient.finalizeCheckoutSession(checkoutSessionId, payload, headers); 1095 | 1096 | response.then(function (result) { 1097 | console.log(result.data); 1098 | }).catch(err => { 1099 | console.log(err); 1100 | }); 1101 | ``` 1102 | 1103 | ## Amazon Checkout v2 Dispute APIs - Create Dispute API 1104 | 1105 | ```js 1106 | const fs = require('fs'); 1107 | const uuidv4 = require('uuid/v4'); 1108 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 1109 | 1110 | const config = { 1111 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 1112 | privateKey: fs.readFileSync('tst/private.pem'), 1113 | region: 'YOUR_REGION_CODE', 1114 | sandbox: true, 1115 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 1116 | }; 1117 | 1118 | const payload = { 1119 | 'chargeId': 'S01-0000000-0000000-C000000', 1120 | 'providerMetadata': { 1121 | 'providerDisputeId': 'XXXXXXXXXXXX' 1122 | }, 1123 | 'disputeAmount': { 1124 | 'amount': '1', 1125 | 'currencyCode': 'JPY' 1126 | }, 1127 | 'filingReason': 'ProductNotReceived', 1128 | 'filingTimestamp': Date.now(), 1129 | 'statusDetails': { 1130 | 'state': 'ActionRequired' 1131 | }, 1132 | 'merchantResponseDeadline': Date.now()+ (14 * 24 * 60 * 60 * 1000) 1133 | }; 1134 | 1135 | const headers = { 1136 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 1137 | }; 1138 | 1139 | const testPayClient = new Client.WebStoreClient(config); 1140 | const response = testPayClient.createDispute(payload, headers); 1141 | 1142 | response.then(function (result) { 1143 | console.log(result.data); 1144 | }).catch(err => { 1145 | console.log(err); 1146 | }); 1147 | ``` 1148 | 1149 | ## Amazon Checkout v2 Dispute APIs - Get Dispute API 1150 | 1151 | ```js 1152 | const fs = require('fs'); 1153 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 1154 | 1155 | const config = { 1156 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 1157 | privateKey: fs.readFileSync('tst/private.pem'), 1158 | region: 'YOUR_REGION_CODE', 1159 | sandbox: true, 1160 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 1161 | }; 1162 | 1163 | const disputeId = 'S01-0000000-0000000-B000000' 1164 | 1165 | const testPayClient = new Client.WebStoreClient(config); 1166 | const response = testPayClient.getDispute(disputeId); 1167 | 1168 | response.then(function (result) { 1169 | console.log(result.data); 1170 | }).catch(err => { 1171 | console.log(err); 1172 | }); 1173 | ``` 1174 | 1175 | ## Amazon Checkout v2 Dispute APIs - Update Dispute API 1176 | 1177 | ```js 1178 | const fs = require('fs'); 1179 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 1180 | 1181 | const config = { 1182 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 1183 | privateKey: fs.readFileSync('tst/private.pem'), 1184 | region: 'YOUR_REGION_CODE', 1185 | sandbox: true, 1186 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 1187 | }; 1188 | 1189 | const payload = { 1190 | "statusDetails": { 1191 | "resolution": "MerchantWon", 1192 | "state": "Resolved", 1193 | "reasonCode": "MerchantAcceptedDispute", 1194 | "reasonDescription": "Merchant accepted the dispute request" 1195 | }, 1196 | "closureTimestamp": Date.now() 1197 | }; 1198 | 1199 | const disputeId = 'S01-0000000-0000000-B000000' 1200 | 1201 | const testPayClient = new Client.WebStoreClient(config); 1202 | const response = testPayClient.updateDispute(disputeId,payload); 1203 | 1204 | response.then(function (result) { 1205 | console.log(result.data); 1206 | }).catch(err => { 1207 | console.log(err); 1208 | }); 1209 | ``` 1210 | 1211 | ## Amazon Checkout v2 Dispute APIs - Contest Dispute API 1212 | 1213 | ```js 1214 | const fs = require('fs'); 1215 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 1216 | 1217 | const config = { 1218 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 1219 | privateKey: fs.readFileSync('tst/private.pem'), 1220 | region: 'YOUR_REGION_CODE', 1221 | sandbox: true, 1222 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 1223 | }; 1224 | 1225 | const payload = { 1226 | "merchantEvidences": [ 1227 | { 1228 | "evidenceType" : "TrackingNumber", 1229 | "fileId": "20ca8c0f-3778-1b5a-8598-3d38cfdc4bde", 1230 | "evidenceText": "raw text supporting merchant evidence" 1231 | } 1232 | ] 1233 | }; 1234 | 1235 | const disputeId = 'S01-0000000-0000000-B000000' 1236 | 1237 | const testPayClient = new Client.WebStoreClient(config); 1238 | const response = testPayClient.contestDispute(disputeId,payload); 1239 | 1240 | response.then(function (result) { 1241 | console.log(result.data); 1242 | }).catch(err => { 1243 | console.log(err); 1244 | }); 1245 | ``` 1246 | 1247 | ## Amazon Checkout v2 File APIs - File API 1248 | 1249 | ```js 1250 | const fs = require('fs'); 1251 | const uuidv4 = require('uuid/v4'); 1252 | const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); 1253 | 1254 | const config = { 1255 | publicKeyId: 'YOUR_PUBLIC_KEY_ID', 1256 | privateKey: fs.readFileSync('tst/private.pem'), 1257 | region: 'YOUR_REGION_CODE', 1258 | sandbox: true, 1259 | algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified 1260 | }; 1261 | 1262 | const payload = { 1263 | "type" : "jpg", 1264 | "purpose" : "disputeEvidence" 1265 | }; 1266 | 1267 | const headers = { 1268 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 1269 | }; 1270 | 1271 | const testPayClient = new Client.WebStoreClient(config); 1272 | const response = testPayClient.uploadFile(payload,headers); 1273 | 1274 | response.then(function (result) { 1275 | console.log(result.data); 1276 | }).catch(err => { 1277 | console.log(err); 1278 | }); 1279 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@amazonpay/amazon-pay-api-sdk-nodejs", 3 | "version": "2.3.3", 4 | "description": "Amazon Pay Checkout V2 Integration", 5 | "main": "src/client.js", 6 | "directories": {}, 7 | "dependencies": { 8 | "axios": "^0.21.2", 9 | "uuid": "^3.3.3" 10 | }, 11 | "devDependencies": { 12 | "chai": "^4.2.0", 13 | "mocha": "^10.0.0" 14 | }, 15 | "scripts": { 16 | "test": "mocha tst/ --timeout 15000" 17 | }, 18 | "author": { 19 | "name": "Amazon Pay API SDK", 20 | "email": "amazon-pay-sdk@amazon.com" 21 | }, 22 | "license": "Apache-2.0" 23 | } -------------------------------------------------------------------------------- /src/client.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const helper = require('./clientHelper'); 4 | const constants = require('./constants'); 5 | 6 | class AmazonPayClient { 7 | constructor(configArgs) { 8 | this.configArgs = Object.freeze(configArgs); 9 | } 10 | 11 | /** API to process a request 12 | * - Makes an API Call using the specified options. 13 | * @param {Object} options - The options to make the API Call 14 | * @param {String} options.method - The HTTP request method 15 | * @param {String} options.urlFragment - The URI for the API Call 16 | * @param {String} [options.payload=null] - The payload for the API Call 17 | * @param {Object} [options.headers=null] - The headers for the API Call 18 | * @param {Object} [options.queryParams=null] - The headers for the API Call 19 | **/ 20 | apiCall(options) { 21 | const preparedOptions = helper.prepareOptions(this.configArgs, options); 22 | preparedOptions.headers = helper.signHeaders(this.configArgs, preparedOptions); 23 | return helper.invokeApi(this.configArgs, preparedOptions); 24 | } 25 | 26 | /** Signs the request headers 27 | * - Signs the request provided and returns the signed headers object. 28 | * @param {Object} options - The options to make the API Call 29 | * @param {String} options.method - The HTTP request method 30 | * @param {String} options.urlFragment - The URI for the API Call 31 | * @param {String} [options.payload=null] - The payload for the API Call 32 | * @param {Object} [options.headers=null] - The headers for the API Call 33 | **/ 34 | getSignedHeaders(options) { 35 | const preparedOptions = helper.prepareOptions(this.configArgs, options); 36 | return helper.signHeaders(this.configArgs, preparedOptions); 37 | } 38 | 39 | /** Lets the solution provider get Authorization Token for their merchants if they are granted the delegation. 40 | * - Please note that your solution provider account must have a pre-existing relationship (valid and active MWS authorization token) with the merchant account in order to use this function. 41 | * @param {String} mwsAuthToken - The mwsAuthToken 42 | * @param {String} merchantId - The MerchantId 43 | * @param {Object} [headers=null] - The headers for the request 44 | **/ 45 | getAuthorizationToken(mwsAuthToken, merchantId, headers = null) { 46 | return this.apiCall({ 47 | method: 'GET', 48 | urlFragment: `authorizationTokens/${mwsAuthToken}`, 49 | headers: headers, 50 | queryParams: { 51 | merchantId: merchantId 52 | } 53 | }); 54 | } 55 | 56 | /** Generates static signature for amazon.Pay.renderButton used by checkout.js. 57 | * - Returns signature as string. 58 | * @param {Object} payload - The payload for the request 59 | * @returns {String} signature 60 | **/ 61 | generateButtonSignature(payload) { 62 | return helper.signPayload(this.configArgs, payload); 63 | } 64 | 65 | /** Lets the solution provider make the DeliveryTrackers request with their auth token. 66 | * - Lets you provide shipment tracking information to Amazon Pay so that Amazon Pay will be able to notify buyers on Alexa when shipments are delivered. 67 | * @see https://developer.amazon.com/docs/amazon-pay-onetime/delivery-notifications.html#api-reference 68 | * @param {Object} payload - The payload for the request 69 | * @param {String} payload.amazonOrderReferenceId - The Amazon Order Reference ID or Charge Permission Id associated with the order for which the shipments need to be tracked 70 | * @param {String} payload.trackingNumber - The tracking number for the shipment provided by the shipping company 71 | * @param {Object} payload.carrierCode - The shipping company code used for delivering goods to the customer 72 | * @param {Object} [headers=null] - The headers for the request 73 | **/ 74 | deliveryTrackers(payload, headers = null) { 75 | return this.apiCall({ 76 | method: 'POST', 77 | urlFragment: 'deliveryTrackers', 78 | payload: payload, 79 | headers: headers 80 | }); 81 | } 82 | } 83 | 84 | class InStoreClient extends AmazonPayClient { 85 | constructor(configArgs) { 86 | super(configArgs); 87 | } 88 | 89 | /** API to initiate a purchase with a merchant 90 | * - Initiates a purchase with a merchant. 91 | * @see //TODO Update Live URL 92 | * @param {Object} payload - The payload for the request 93 | * @param {Object} [headers=null] - The headers for the request 94 | **/ 95 | merchantScan(payload, headers = null) { 96 | return this.apiCall({ 97 | method: 'POST', 98 | urlFragment: 'in-store/merchantScan', 99 | payload: payload, 100 | headers: headers 101 | }); 102 | } 103 | 104 | /** API to create Charge to the buyer 105 | * - Creates a charge to the buyer with the requested amount. 106 | * @see //TODO Update Live URL 107 | * @param {Object} payload - The payload for the request 108 | * @param {Object} [headers=null] - The headers for the request 109 | **/ 110 | charge(payload, headers = null) { 111 | return this.apiCall({ 112 | method: 'POST', 113 | urlFragment: 'in-store/charge', 114 | payload: payload, 115 | headers: headers 116 | }); 117 | } 118 | 119 | /** API to create a Refund to the buyer 120 | * - Refunds an amount that was previously charged to the buyer. 121 | * @see //TODO Update Live URL 122 | * @param {Object} payload - The payload for the request 123 | * @param {Object} [headers=null] - The headers for the request 124 | **/ 125 | refund(payload, headers = null) { 126 | return this.apiCall({ 127 | method: 'POST', 128 | urlFragment: 'in-store/refund', 129 | payload: payload, 130 | headers: headers 131 | }); 132 | } 133 | } 134 | 135 | class WebStoreClient extends AmazonPayClient { 136 | constructor(configArgs) { 137 | super(configArgs); 138 | } 139 | 140 | /** API to get the Buyer object 141 | * - Get Buyer details can include buyer ID, name, email address, postal code, and country code 142 | * - when used with the Amazon.Pay.renderButton 'SignIn' productType and corresponding signInScopes 143 | * @param {String} buyerToken - The checkout session Id 144 | * @param {Object} [headers=null] - The headers for the request 145 | **/ 146 | getBuyer(buyerToken, headers = null) { 147 | return this.apiCall({ 148 | method: 'GET', 149 | urlFragment: `buyers/${buyerToken}`, 150 | headers: headers 151 | }); 152 | } 153 | 154 | /** API to create a CheckoutSession object 155 | * - Creates a new CheckoutSession object. 156 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/checkout-session.html#create-checkout-session 157 | * @param {Object} payload - The payload for the request 158 | * @param {Object} headers - The headers for the request 159 | **/ 160 | createCheckoutSession(payload, headers) { 161 | return this.apiCall({ 162 | method: 'POST', 163 | urlFragment: 'checkoutSessions', 164 | payload: payload, 165 | headers: headers 166 | }); 167 | } 168 | 169 | /** API to get the CheckoutSession object 170 | * - Retrives details of a previously created CheckoutSession object. 171 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/checkout-session.html#get-checkout-session 172 | * @param {String} checkoutSessionId - The checkout session Id 173 | * @param {Object} [headers=null] - The headers for the request 174 | **/ 175 | async getCheckoutSession(checkoutSessionId, headers = null) { 176 | const response = await this.apiCall({ 177 | method: 'GET', 178 | urlFragment: `checkoutSessions/${checkoutSessionId}`, 179 | headers: headers 180 | }); 181 | 182 | return helper.enhanceResponseWithShippingAddressList(response); 183 | } 184 | 185 | /** API to update the CheckoutSession object 186 | * - Updates a previously created CheckoutSession object. 187 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/checkout-session.html#update-checkout-session 188 | * @param {String} checkoutSessionId - The checkout session Id 189 | * @param {Object} payload - The payload for the request 190 | * @param {Object} [headers=null] - The headers for the request 191 | **/ 192 | async updateCheckoutSession(checkoutSessionId, payload, headers = null) { 193 | const response = await this.apiCall({ 194 | method: 'PATCH', 195 | urlFragment: `checkoutSessions/${checkoutSessionId}`, 196 | payload: payload, 197 | headers: headers 198 | }); 199 | 200 | return helper.enhanceResponseWithShippingAddressList(response); 201 | } 202 | 203 | /** API to complete a Checkout Session 204 | * - Confirms the completion of buyer checkout. 205 | * @see //TODO Update Live URL 206 | * @param {String} checkoutSessionId - The checkout session Id 207 | * @param {Object} payload - The payload for the request 208 | * @param {Object} [headers=null] - The headers for the request 209 | **/ 210 | async completeCheckoutSession(checkoutSessionId, payload, headers = null) { 211 | const response = await this.apiCall({ 212 | method: 'POST', 213 | urlFragment: `checkoutSessions/${checkoutSessionId}/complete`, 214 | payload: payload, 215 | headers: headers 216 | }); 217 | 218 | return helper.enhanceResponseWithShippingAddressList(response); 219 | } 220 | 221 | // ----------------------------------- Buy Now ----------------------------------- 222 | 223 | /** FinalizeCheckoutSession API which enables Pay to validate payment critical attributes and also update book-keeping attributes present in merchantMetadata 224 | * 225 | * @param {String} checkoutSessionId - The checkout session Id 226 | * @param {Object} payload - The payload for the request 227 | * @param {Object} [headers=null] - The headers for the request 228 | */ 229 | finalizeCheckoutSession(checkoutSessionId, payload, headers = null) { 230 | return this.apiCall({ 231 | method: 'POST', 232 | urlFragment: `checkoutSessions/${checkoutSessionId}/finalize`, 233 | payload: payload, 234 | headers: headers 235 | }); 236 | } 237 | 238 | /** API to get a ChargePermission object 239 | * - Retrives details of a previously created ChargePermission object. 240 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/charge-permission.html#get-charge-permission 241 | * @param {String} chargePermissionId - The charge permission Id 242 | * @param {Object} [headers=null] - The headers for the request 243 | **/ 244 | getChargePermission(chargePermissionId, headers = null) { 245 | return this.apiCall({ 246 | method: 'GET', 247 | urlFragment: `chargePermissions/${chargePermissionId}`, 248 | headers: headers 249 | }); 250 | } 251 | 252 | /** API to update a ChargePermission object 253 | * - Updates a previously created ChargePermission object. 254 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/charge-permission.html#update-charge-permission 255 | * @param {String} chargePermissionId - The charge permission Id 256 | * @param {Object} payload - The payload for the request 257 | * @param {Object} [headers=null] - The headers for the request 258 | **/ 259 | updateChargePermission(chargePermissionId, payload, headers = null) { 260 | return this.apiCall({ 261 | method: 'PATCH', 262 | urlFragment: `chargePermissions/${chargePermissionId}`, 263 | payload: payload, 264 | headers: headers 265 | }); 266 | } 267 | 268 | /** API to close a ChargePermission object 269 | * - Closes a perviously created ChargePermission object. 270 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/charge-permission.html#close-charge-permission 271 | * @param {String} chargePermissionId - The charge permission Id 272 | * @param {Object} payload - The payload for the request 273 | * @param {Object} [headers=null] - The headers for the request 274 | **/ 275 | closeChargePermission(chargePermissionId, payload, headers = null) { 276 | return this.apiCall({ 277 | method: 'DELETE', 278 | urlFragment: `chargePermissions/${chargePermissionId}/close`, 279 | payload: payload, 280 | headers: headers 281 | }); 282 | } 283 | 284 | /** API to create a Charge object 285 | * - Creates a new Charge object. 286 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/charge.html#create-charge 287 | * @param {Object} payload - The payload for the request 288 | * @param {Object} headers - The headers for the request 289 | **/ 290 | createCharge(payload, headers) { 291 | return this.apiCall({ 292 | method: 'POST', 293 | urlFragment: 'charges', 294 | payload: payload, 295 | headers: headers 296 | }); 297 | } 298 | 299 | /** API to get the Charge object 300 | * - Retrieves a perviously created Charge object. 301 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/charge.html#get-charge 302 | * @param {String} chargeId - The charge Id 303 | * @param {Object} [headers=null] - The headers for the request 304 | **/ 305 | getCharge(chargeId, headers = null) { 306 | return this.apiCall({ 307 | method: 'GET', 308 | urlFragment: `charges/${chargeId}`, 309 | headers: headers 310 | }); 311 | } 312 | 313 | /** Amazon Checkout v2 - Update Charge 314 | * 315 | * The updateCharge operation is used to update the charge status of any PSP (Payment Service Provider) processed payment method (PPM) transactions. 316 | * Please note that is API is supported only for PSPs (Payment Service Provider) 317 | * 318 | * @param {String} chargeId - The charge Id 319 | * @param {Object} payload - The payload for the request 320 | * @param {Object} [headers=null] - The headers for the request 321 | * 322 | */ 323 | updateCharge(chargeId, payload,headers) { 324 | return this.apiCall({ 325 | method: 'PATCH', 326 | urlFragment: `charges/${chargeId}`, 327 | payload: payload, 328 | headers: headers 329 | }); 330 | } 331 | 332 | /** API to create a captureCharge request 333 | * - Captures an existing charge 334 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/charge.html#capture-charge 335 | * @param {String} chargeId - The charge Id 336 | * @param {Object} payload - The payload for the request 337 | * @param {Object} [headers=null] - The headers for the request 338 | **/ 339 | captureCharge(chargeId, payload, headers = null) { 340 | return this.apiCall({ 341 | method: 'POST', 342 | urlFragment: `charges/${chargeId}/capture`, 343 | payload: payload, 344 | headers: headers 345 | }); 346 | } 347 | 348 | /** API to create a cancelCharge request 349 | * - Cancels an existing charge. 350 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/charge.html#cancel-charge 351 | * @param {String} chargeId - The charge Id 352 | * @param {Object} payload - The payload for the request 353 | * @param {Object} [headers=null] - The headers for the request 354 | **/ 355 | cancelCharge(chargeId, payload, headers = null) { 356 | return this.apiCall({ 357 | method: 'DELETE', 358 | urlFragment: `charges/${chargeId}/cancel`, 359 | payload: payload, 360 | headers: headers 361 | }); 362 | } 363 | 364 | /** API to create a Refund object 365 | * - Generates a refund. 366 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/refund.html#create-refund 367 | * @param {Object} payload - The payload for the request 368 | * @param {Object} headers - The headers for the request 369 | **/ 370 | createRefund(payload, headers) { 371 | return this.apiCall({ 372 | method: 'POST', 373 | urlFragment: 'refunds', 374 | payload: payload, 375 | headers: headers 376 | }); 377 | } 378 | 379 | /** API to get a Refund object 380 | * - Retreives details of an existing refund. 381 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/refund.html#get-refund 382 | * @param {String} refundId - The refund Id 383 | * @param {Object} [headers=null] - The headers for the request 384 | **/ 385 | getRefund(refundId, headers = null) { 386 | return this.apiCall({ 387 | method: 'GET', 388 | urlFragment: `refunds/${refundId}`, 389 | headers: headers 390 | }); 391 | } 392 | 393 | 394 | // ----------------------------------- CV2 REPORTING APIS ----------------------------------- 395 | 396 | 397 | /** API to get Reports 398 | * - retrieves details for the reports that match the filters that you specify. 399 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-reports 400 | * @param {Object} [queryParameters=null] - The queryParameters for the request 401 | * @param {Object} [headers=null] - The headers for the request 402 | **/ 403 | getReports(queryParameters = null, headers = null) { 404 | if(queryParameters) { 405 | const {reportTypes, processingStatuses } = queryParameters; 406 | if(Array.isArray(reportTypes)){ 407 | queryParameters.reportTypes = reportTypes.toString(); 408 | } 409 | if(Array.isArray(processingStatuses)){ 410 | queryParameters.processingStatuses = processingStatuses.toString(); 411 | } 412 | } 413 | return this.apiCall({ 414 | method: 'GET', 415 | urlFragment: `reports`, 416 | headers: headers, 417 | queryParams: queryParameters 418 | }); 419 | } 420 | 421 | 422 | /** API to get Report by Id 423 | * - retrieves report details for the given reportId. 424 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-report-by-id 425 | * @param {String} reportId - The Report Id 426 | * @param {Object} [headers=null] - The headers for the request 427 | **/ 428 | getReportById(reportId, headers = null) { 429 | return this.apiCall({ 430 | method: 'GET', 431 | urlFragment: `reports/${reportId}`, 432 | headers: headers 433 | }); 434 | } 435 | 436 | 437 | /** API to get Report Document 438 | * - returns the pre-signed S3 URL for the report. The report can be downloaded using this URL. 439 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-report-document 440 | * @param {String} reportDocumentId - The Report Id 441 | * @param {Object} [headers=null] - The headers for the request 442 | **/ 443 | getReportDocument(reportDocumentId, headers = null) { 444 | return this.apiCall({ 445 | method: 'GET', 446 | urlFragment: `report-documents/${reportDocumentId}`, 447 | headers: headers 448 | }); 449 | } 450 | 451 | 452 | /** API to get Report Schedules 453 | * - returns report schedule details that match the filters criteria specified. 454 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-report-schedules 455 | * @param {String} [reportTypes=null] - The Report Id 456 | * @param {Object} [headers=null] - The headers for the request 457 | **/ 458 | getReportSchedules(reportTypes = null, headers = null) { 459 | const queryParameters = { 460 | 'reportTypes': Array.isArray(reportTypes) ? reportTypes.toString() : reportTypes 461 | }; 462 | return this.apiCall({ 463 | method: 'GET', 464 | urlFragment: `report-schedules`, 465 | headers: headers, 466 | queryParams: reportTypes ? queryParameters : reportTypes 467 | }); 468 | } 469 | 470 | 471 | /** API to get Report Schedule by Id 472 | * - returns the report schedule details that match the given ID. 473 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-report-schedule-by-id 474 | * @param {String} reportScheduleId - The Report Schedule Id 475 | * @param {Object} [headers=null] - The headers for the request 476 | **/ 477 | getReportScheduleById(reportScheduleId, headers = null) { 478 | return this.apiCall({ 479 | method: 'GET', 480 | urlFragment: `report-schedules/${reportScheduleId}`, 481 | headers: headers 482 | }); 483 | } 484 | 485 | 486 | /** API to create Report 487 | * - submits a request to generate a report based on the reportType and date range specified. 488 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#create-report 489 | * @param {Object} requestPayload - The payload for the request 490 | * @param {Object} headers - The headers for the request 491 | **/ 492 | createReport(requestPayload, headers) { 493 | return this.apiCall({ 494 | method: 'POST', 495 | urlFragment: `reports`, 496 | payload: requestPayload, 497 | headers: headers 498 | }); 499 | } 500 | 501 | 502 | /** API to create Report Schedule 503 | * - creates a report schedule for the given reportType. Only one schedule per report type allowed. 504 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#create-report-schedules 505 | * @param {Object} requestPayload - The payload for the request 506 | * @param {Object} headers - The headers for the request 507 | **/ 508 | createReportSchedule(requestPayload, headers) { 509 | return this.apiCall({ 510 | method: 'POST', 511 | urlFragment: `report-schedules`, 512 | payload: requestPayload, 513 | headers: headers 514 | }); 515 | } 516 | 517 | 518 | /** API to cancel Report Schedule 519 | * - cancels the report schedule with the given reportScheduleId. 520 | * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#cancel-report-schedule 521 | * @param {String} reportScheduleId - The Report Schedule Id 522 | * @param {Object} [headers=null] - The headers for the request 523 | **/ 524 | cancelReportSchedule(reportScheduleId, headers = null) { 525 | return this.apiCall({ 526 | method: 'DELETE', 527 | urlFragment: `report-schedules/${reportScheduleId}`, 528 | headers: headers 529 | }); 530 | } 531 | 532 | // ----------------------------------- Merchant Onboarding & Account Management APIs -------------------- 533 | 534 | /** 535 | * Creates a non-logginable account for your merchant partners. These would be special accounts through which Merchants would not be able to login to Amazon or access Seller Central. 536 | * 537 | * @param {Object} payload - The payload for the request 538 | * @param {Object} [headers=null] - The headers for the request 539 | */ 540 | registerAmazonPayAccount(payload, headers = null) { 541 | return this.apiCall({ 542 | method: 'POST', 543 | urlFragment: `${constants.ACCOUNT_MANAGEMENT}`, 544 | payload: payload, 545 | headers: headers 546 | }); 547 | } 548 | 549 | /** 550 | * Updates a merchant account for the given Merchant Account ID. We would be allowing our partners to update only a certain set of fields which won’t change the legal business entity itself. 551 | * 552 | * @param {String} merchantAccountId - Internal Merchant Account ID 553 | * @param {Object} payload - The payload for the request 554 | * @param {Object} [headers=null] - The headers for the request 555 | */ 556 | updateAmazonPayAccount(merchantAccountId, payload, headers = null) { 557 | return this.apiCall({ 558 | method: 'PATCH', 559 | urlFragment: `${constants.ACCOUNT_MANAGEMENT}/${merchantAccountId}`, 560 | payload: payload, 561 | headers: headers 562 | }); 563 | } 564 | 565 | /** 566 | * Deletes the Merchant account for the given Merchant Account ID. Partners can close the merchant accounts created for their merchant partners. 567 | * 568 | * @param {String} merchantAccountId - Internal Merchant Account ID 569 | * @param {Object} [headers=null] - The headers for the requestrs 570 | */ 571 | deleteAmazonPayAccount(merchantAccountId, headers = null) { 572 | return this.apiCall({ 573 | method: 'DELETE', 574 | urlFragment: `${constants.ACCOUNT_MANAGEMENT}/${merchantAccountId}`, 575 | headers: headers 576 | }); 577 | } 578 | 579 | // ----------------------------------- Dispute APIs ----------------------------------- 580 | 581 | /** Amazon Checkout v2 - Create Dispute 582 | * 583 | * The createDispute operation is used to notify Amazon of a newly created chargeback dispute by a buyer on a transaction 584 | * processed by the PSP (Payment Service Provider), ensuring the dispute is properly accounted for in the Amazon Pay systems. 585 | * 586 | * @param {Object} payload - The payload for the request 587 | * @param {Object} headers - The headers for the request 588 | * 589 | */ 590 | createDispute(payload, headers) { 591 | return this.apiCall({ 592 | method: 'POST', 593 | urlFragment: `${constants.DISPUTES}`, 594 | payload: payload, 595 | headers: headers 596 | }); 597 | } 598 | 599 | /** Amazon Checkout v2 - Get Dispute 600 | * 601 | * The getDispute operation is used to retrieve details of a chargeback dispute associated with a specific order 602 | * 603 | * @param {String} disputeId - The dispute ID 604 | * @param {Object} [headers=null] - The headers for the request 605 | */ 606 | getDispute(disputeId, headers = null){ 607 | return this.apiCall({ 608 | method: 'GET', 609 | urlFragment: `${constants.DISPUTES}/${disputeId}`, 610 | headers: headers 611 | }) 612 | } 613 | 614 | /** Amazon Checkout v2 - Update Dispute 615 | * 616 | * The updateDispute operation is used to notify Amazon of the closure status of a chargeback dispute initiated by a 617 | * buyer for orders processed by a partner PSP (Payment Service Provider), ensuring proper accounting within the Amazon systems. 618 | * 619 | * @param {String} disputeId - The dispute ID 620 | * @param {Object} payload - The payload for the request 621 | * @param {Object} [headers=null] - The headers for the request 622 | * 623 | */ 624 | updateDispute(disputeId, payload, headers) { 625 | return this.apiCall({ 626 | method: 'PATCH', 627 | urlFragment: `${constants.DISPUTES}/${disputeId}`, 628 | payload: payload, 629 | headers: headers 630 | }); 631 | } 632 | 633 | /** Amazon Checkout v2 - Contest Dispute 634 | * 635 | * The contestDispute operation is used by the partner, on behalf of the merchant, to formally contest a dispute 636 | * managed by Amazon, requiring the submission of necessary evidence files within the specified 637 | * Dispute Window (11 days for Chargeback, 7 days for A-Z Claims). 638 | * 639 | * @param {String} disputeId - The dispute ID 640 | * @param {Object} payload - The payload for the request 641 | * @param {Object} [headers=null] - The headers for the request 642 | * 643 | */ 644 | contestDispute(disputeId, payload, headers) { 645 | return this.apiCall({ 646 | method: 'POST', 647 | urlFragment: `${constants.DISPUTES}/${disputeId}/${constants.CONTEXT}`, 648 | payload: payload, 649 | headers: headers 650 | }); 651 | } 652 | 653 | // ----------------------------------- File APIs ----------------------------------- 654 | 655 | /** Amazon Checkout v2 - Upload File 656 | * 657 | * The uploadFile operation is utilised by PSPs (Payment Service Provider) to upload file-based evidence when a 658 | * merchant contests a dispute, providing the necessary reference ID to the evidence file as part of 659 | * the Update Dispute API process. 660 | * 661 | * @param {Object} payload - The payload for the request 662 | * @param {Object} headers - The headers for the request 663 | * 664 | */ 665 | uploadFile(payload, headers) { 666 | return this.apiCall({ 667 | method: 'POST', 668 | urlFragment: `${constants.FILES}`, 669 | payload: payload, 670 | headers: headers 671 | }); 672 | } 673 | } 674 | 675 | module.exports = { 676 | AmazonPayClient: AmazonPayClient, 677 | InStoreClient: InStoreClient, 678 | WebStoreClient: WebStoreClient 679 | }; 680 | -------------------------------------------------------------------------------- /src/clientHelper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const constants = require('./constants'); 4 | const crypto = require('crypto'); 5 | const axios = require('axios'); 6 | 7 | module.exports = { 8 | signHeaders: signHeaders, 9 | signPayload: signPayload, 10 | retryLogic: retryLogic, 11 | sendRequest: sendRequest, 12 | invokeApi: invokeApi, 13 | prepareOptions: prepareOptions, 14 | enhanceResponseWithShippingAddressList: enhanceResponseWithShippingAddressList 15 | } 16 | 17 | function getTimestamp() { 18 | const date = new Date(); 19 | return date.toISOString().split('.')[0] + 'Z'; 20 | } 21 | 22 | function getAPIEndpointBaseURL(configArgs) { 23 | if ((configArgs.overrideServiceUrl) && (configArgs.overrideServiceUrl.length > 0)) { 24 | process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0; // devo environment using self-signed certificate 25 | return configArgs.overrideServiceUrl; 26 | } else 27 | return constants.API_ENDPOINTS[constants.REGION_MAP[configArgs.region.toLowerCase()]]; 28 | } 29 | 30 | function invokeApi(configArgs, apiOptions) { 31 | 32 | const options = { 33 | method: apiOptions.method, 34 | json: false, 35 | headers: apiOptions.headers, 36 | url: `https://${getAPIEndpointBaseURL(configArgs)}/${apiOptions.urlFragment}${getQueryString(apiOptions.queryParams)}`, 37 | data: apiOptions.payload 38 | }; 39 | 40 | const response = this.retryLogic(options, 1); 41 | 42 | return response; 43 | } 44 | 45 | function getQueryString(requestParams) { 46 | if (requestParams) return `?${getParametersAsString(requestParams)}`; 47 | return ''; 48 | } 49 | 50 | function getParametersAsString(requestParams) { 51 | if (!requestParams) return ''; 52 | 53 | let queryParams = []; 54 | Object.keys(requestParams).sort().forEach(function (param) { 55 | queryParams.push(`${param}=${encodeURIComponent(requestParams[param])}`); 56 | }); 57 | return queryParams.join('&'); 58 | } 59 | 60 | function prepareOptions(configArgs, options) { 61 | options.headers = options.headers || {}; 62 | 63 | // if user doesn't pass in a string, assume it's a JS object and convert it to a JSON string 64 | if (!(typeof options.payload === 'string' || options.payload instanceof String)) { 65 | options.payload = JSON.stringify(options.payload); 66 | } 67 | // Condition to validate PublicKeyId is Environment specific 68 | if (isEnvSpecificPublicKeyId(configArgs['publicKeyId'])) { 69 | options.urlFragment = `${constants.API_VERSION}/${options.urlFragment}`; 70 | } else { 71 | if (configArgs['sandbox'] === true || configArgs['sandbox'] === 'true') { 72 | options.urlFragment = `sandbox/${constants.API_VERSION}/${options.urlFragment}`; 73 | } else { 74 | options.urlFragment = `live/${constants.API_VERSION}/${options.urlFragment}`; 75 | } 76 | } 77 | return options; 78 | } 79 | 80 | // Method used to validate whether PublicKeyId starts with prefix LIVE or SANDBOX 81 | function isEnvSpecificPublicKeyId(publicKeyId) { 82 | return publicKeyId.toUpperCase().startsWith('LIVE') || publicKeyId.toUpperCase().startsWith('SANDBOX') 83 | } 84 | 85 | function sign(privateKey, stringToSign, algorithm) { 86 | const sign = crypto.createSign('RSA-SHA256').update(stringToSign); 87 | return sign.sign({ 88 | key: privateKey, 89 | padding: crypto.constants.RSA_PKCS1_PSS_PADDING, 90 | saltLength: algorithm.saltLength, 91 | }, 'base64'); 92 | } 93 | 94 | function getAlgorithm(algorithm) { 95 | if (!algorithm) return constants.AMAZON_SIGNATURE_ALGORITHM.DEFAULT; 96 | 97 | for (const [key, value] of Object.entries(constants.AMAZON_SIGNATURE_ALGORITHM)) { 98 | if (value.name === algorithm) { 99 | return constants.AMAZON_SIGNATURE_ALGORITHM[key]; 100 | } 101 | } 102 | throw "Not a valid algorithm"; 103 | } 104 | 105 | function retryLogic(options, count) { 106 | const response = this.sendRequest(options, count); 107 | 108 | if (count > constants.RETRIES) { 109 | return response.then(function (result) { 110 | return result; 111 | }).catch(err => { 112 | return Promise.reject(err); 113 | }); 114 | } 115 | 116 | return response.then(function (result) { 117 | return result; 118 | }).catch(err => { 119 | if (response.statusCode === 408 || response.statusCode === 425 || response.statusCode === 429 || response.statusCode >= 500) { 120 | return this.retryLogic(options, count += 1); 121 | } else { 122 | return Promise.reject(err); 123 | } 124 | }) 125 | } 126 | 127 | function sendRequest(options, count) { 128 | const delayTime = count === 1 ? 0 : (2 ** (count - 1)) * 1000; 129 | 130 | return new Promise(function (resolve, reject) { 131 | setTimeout(function () { 132 | axios.request(options).then(response => { 133 | if (response.status >= 400) { 134 | reject(response); 135 | } else { 136 | resolve(response); 137 | } 138 | }).catch(error => { 139 | reject(error); 140 | }); 141 | }, delayTime); 142 | }); 143 | } 144 | 145 | /* Expected options: 146 | options.method 147 | options.urlFragment 148 | options.payload 149 | options.headers 150 | */ 151 | function signHeaders(configArgs, options) { 152 | const headers = {}; 153 | 154 | Object.assign(headers, options.headers); 155 | 156 | headers['x-amz-pay-region'] = constants.REGION_MAP[configArgs.region.toLowerCase()]; 157 | headers['x-amz-pay-host'] = getAPIEndpointBaseURL(configArgs); 158 | headers['x-amz-pay-date'] = getTimestamp(); 159 | headers['content-type'] = 'application/json'; 160 | headers['accept'] = 'application/json'; 161 | headers['user-agent'] = `amazon-pay-api-sdk-nodejs/${constants.SDK_VERSION} (JS/${process.versions.node}; ${process.platform})`; 162 | 163 | const lowercaseSortedHeaderKeys = Object.keys(headers).sort(function (a, b) { 164 | return a.toLowerCase().localeCompare(b.toLowerCase()); 165 | }); 166 | const signedHeaders = lowercaseSortedHeaderKeys.join(';'); 167 | 168 | let payload = options.payload; 169 | if (payload === null || payload === undefined) { 170 | payload = ''; 171 | } 172 | 173 | let canonicalRequest = options.method + '\n/' 174 | + options.urlFragment + '\n' 175 | + getParametersAsString(options.queryParams) + '\n'; 176 | lowercaseSortedHeaderKeys.forEach(item => canonicalRequest += item.toLowerCase() + ':' + headers[item] + '\n'); 177 | canonicalRequest += '\n' + signedHeaders + '\n' + crypto.createHash('SHA256').update(payload).digest('hex'); 178 | 179 | const algorithm = getAlgorithm(configArgs.algorithm); 180 | const stringToSign = algorithm.name + '\n' + 181 | crypto.createHash('SHA256').update(canonicalRequest).digest('hex'); 182 | 183 | const signature = sign(configArgs.privateKey, stringToSign, algorithm); 184 | 185 | headers['authorization'] = algorithm.name 186 | + ' PublicKeyId=' + configArgs['publicKeyId'] 187 | + ', SignedHeaders=' + signedHeaders 188 | + ', Signature=' + signature; 189 | 190 | return headers; 191 | } 192 | 193 | function signPayload(configArgs, payload) { 194 | // if user doesn't pass in a string, assume it's a JS object and convert it to a JSON string 195 | if (!(typeof payload === 'string' || payload instanceof String)) { 196 | payload = JSON.stringify(payload); 197 | } 198 | const algorithm = getAlgorithm(configArgs.algorithm); 199 | const stringToSign = algorithm.name + '\n' + 200 | crypto.createHash('SHA256').update(payload).digest('hex'); 201 | 202 | return sign(configArgs.privateKey, stringToSign, algorithm); 203 | } 204 | 205 | function enhanceResponseWithShippingAddressList(response) { 206 | if (response.data.shippingAddressList != null) { 207 | response.data.shippingAddressList = response.data.shippingAddressList.map(shippingAddress => JSON.parse(shippingAddress)); 208 | } 209 | return response; 210 | } 211 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | SDK_VERSION: '2.3.3', 5 | API_VERSION: 'v2', 6 | RETRIES: 3, 7 | API_ENDPOINTS: { 8 | na: 'pay-api.amazon.com', 9 | eu: 'pay-api.amazon.eu', 10 | jp: 'pay-api.amazon.jp' 11 | }, 12 | REGION_MAP: { 13 | na: 'na', 14 | us: 'na', 15 | de: 'eu', 16 | uk: 'eu', 17 | eu: 'eu', 18 | jp: 'jp' 19 | }, 20 | AMAZON_SIGNATURE_ALGORITHM: { 21 | DEFAULT: { name: 'AMZN-PAY-RSASSA-PSS', saltLength: 20 }, 22 | V2: { name: 'AMZN-PAY-RSASSA-PSS-V2', saltLength: 32 } 23 | }, 24 | ACCOUNT_MANAGEMENT: 'merchantAccounts', 25 | DISPUTES: 'disputes', 26 | CONTEXT: 'contest', 27 | FILES: 'files' 28 | }; 29 | -------------------------------------------------------------------------------- /tst/Readme.md: -------------------------------------------------------------------------------- 1 | # Amazon Pay SDK - V2 - Node JS - Test 2 | 3 | # API's Included to Test 4 | #### WebStoreClient 5 | - CreateCheckoutSession 6 | - GetCheckoutSession 7 | - UpdateCheckoutSession 8 | - GetChargePermission 9 | - UpdateChargePermission 10 | - CloseChargePermission 11 | - CreateCharge 12 | - GetCharge 13 | - CaptureCharge 14 | - CreateRefund 15 | - GetRefund 16 | 17 | #### InStoreClient 18 | - MerchantScan 19 | - Charge 20 | - Refund 21 | 22 | ### Installation 23 | Requires node should be installed in machine. 24 | Install the dependencies 25 | ```sh 26 | $ npm install 27 | ``` 28 | 29 | ### Plugins Used 30 | SDK is currently extended with the following plugins. 31 | 32 | | Plugin | README | 33 | | ------ | ------ | 34 | | Mocha | https://mochajs.org/ | 35 | | Chai | https://www.chaijs.com/ | 36 | 37 | ### Testing 38 | - Provide the Public Key ID, Region & Sandbox (true or false) in config.js 39 | - Replace AmazonPay_publicKeyId.pem with the path to your private key file 40 | - Get ChargePermission ID from Test Integration and provide it in webStoreClientTest.js file 41 | - Open your favorite Terminal and run these commands. 42 | 43 | Command : 44 | ```sh 45 | $ npm test 46 | ``` 47 | ### Sample Output 48 | ```sh 49 | 50 | InStore Client Test Cases 51 | ✓ Validating Merchant Scan API (1175ms) 52 | ✓ Validating Charge API (1443ms) 53 | ✓ Validating Refund API (871ms) 54 | 55 | WebStore Client Test Cases - Checkout Session APIs 56 | ✓ Validating Create Checkout Session API (1027ms) 57 | ✓ Validating Get Checkout Session API (517ms) 58 | ✓ Validating Update Checkout Session API (528ms) 59 | 60 | WebStore Client Test Cases - Charge Permission APIs 61 | ✓ Validating Get Charge Permission API (1395ms) 62 | ✓ Validating Update Charge Permission API (1022ms) 63 | 64 | WebStore Client Test Cases - Charge APIs 65 | ✓ Validating Create Charge API (1361ms) 66 | ✓ Validating Get Charge API (734ms) 67 | ✓ Validating Capture Charge API (1080ms) 68 | 69 | WebStore Client Test Cases - Refund APIs 70 | ✓ Validating Create Refund API (1020ms) 71 | ✓ Validating Get Refund API (718ms) 72 | 73 | 13 passing (11s) 74 | ``` -------------------------------------------------------------------------------- /tst/amazonPayClientTest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Including Required Modules 4 | const Client = require('../src/client'); 5 | const config = require('./config'); 6 | const configWithAlgorithm = require('./configWithAlgorithm'); 7 | const assert = require('assert'); 8 | const crypto = require('crypto'); 9 | const fs = require('fs'); 10 | 11 | const publicKey = ``; // Provide public key here to run the tests 12 | 13 | const generateButtonSignaturePayloadObject = { 14 | storeId: 'amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 15 | webCheckoutDetails: { 16 | checkoutReviewReturnUrl: 'https://localhost/test/CheckoutReview.php', 17 | checkoutResultReturnUrl: 'https://localhost/test/CheckoutResult.php' 18 | } 19 | }; 20 | const generateButtonSignaturePayloadString = '{"storeId":"amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","webCheckoutDetails":{"checkoutReviewReturnUrl":"https://localhost/test/CheckoutReview.php","checkoutResultReturnUrl":"https://localhost/test/CheckoutResult.php"}}'; 21 | const generateButtonSignaturePayloadEscapedString = '{"storeId\":\"amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\"webCheckoutDetails\":{\"checkoutReviewReturnUrl\":\"https:\/\/localhost\/test\/CheckoutReview.php\",\"checkoutResultReturnUrl\":\"https:\/\/localhost\/test\/CheckoutResult.php\"}}'; 22 | const expectedStringToSign = `AMZN-PAY-RSASSA-PSS 23 | 8dec52d799607be40f82d5c8e7ecb6c171e6591c41b1111a576b16076c89381c`; 24 | const expectedStringToSignWithV2Algorithm = `AMZN-PAY-RSASSA-PSS-V2 25 | 8dec52d799607be40f82d5c8e7ecb6c171e6591c41b1111a576b16076c89381c`; 26 | 27 | const mwsAuthToken = ''; // Provide public key here to run the tests 28 | const merchantId = ''; // Provide merchantId 29 | 30 | function verify(signature, algorithm = null) { 31 | var stringToSign = ''; 32 | if (algorithm) { 33 | stringToSign = expectedStringToSignWithV2Algorithm; 34 | } else { 35 | stringToSign = expectedStringToSign; 36 | } 37 | var verifier = crypto.createVerify('RSA-SHA256').update(stringToSign); 38 | return verifier.verify({ 39 | key: publicKey, 40 | padding: crypto.constants.RSA_PKCS1_PSS_PADDING, 41 | }, signature, 'base64'); 42 | } 43 | 44 | describe('AmazonPay Client Test Cases - Generate Button Signature', () => { 45 | before(function () { 46 | if (!publicKey) { 47 | console.error('Please provide publicKey before executing these test cases'); 48 | this.skip(); 49 | } 50 | }); 51 | it('Validating Generate Button Signature Method', (done) => { 52 | const amazonPayCLient = new Client.AmazonPayClient(config); 53 | const signatureOne = amazonPayCLient.generateButtonSignature(generateButtonSignaturePayloadObject); 54 | const signatureTwo = amazonPayCLient.generateButtonSignature(generateButtonSignaturePayloadString); 55 | const signatureThree = amazonPayCLient.generateButtonSignature(generateButtonSignaturePayloadEscapedString); 56 | assert.ok(verify(signatureOne), 'Failed for JS object payload'); 57 | assert.ok(verify(signatureTwo), 'Failed for string payload'); 58 | assert.ok(verify(signatureThree), 'Failed for escaped string payload'); 59 | 60 | //Test with V2 Algorithm passed in config 61 | const amazonPayCLientWithAlgorithm = new Client.AmazonPayClient(configWithAlgorithm); 62 | const signatureOneWithAlgorithm = amazonPayCLientWithAlgorithm.generateButtonSignature(generateButtonSignaturePayloadObject); 63 | const signatureTwoWithAlgorithm = amazonPayCLientWithAlgorithm.generateButtonSignature(generateButtonSignaturePayloadString); 64 | const signatureThreeWithAlgorithm = amazonPayCLientWithAlgorithm.generateButtonSignature(generateButtonSignaturePayloadEscapedString); 65 | assert.ok(verify(signatureOneWithAlgorithm, configWithAlgorithm['algorithm']), 'Failed for JS object payload'); 66 | assert.ok(verify(signatureTwoWithAlgorithm, configWithAlgorithm['algorithm']), 'Failed for string payload'); 67 | assert.ok(verify(signatureThreeWithAlgorithm, configWithAlgorithm['algorithm']), 'Failed for escaped string payload'); 68 | done(); 69 | }); 70 | }); 71 | 72 | describe('AmazonPay Client Test Cases - Get Authorization Token', () => { 73 | before(function () { 74 | if (!mwsAuthToken || !merchantId) { 75 | console.error('Please provide mwsAuthToken and merchantId before executing these test cases'); 76 | this.skip(); 77 | } 78 | }); 79 | it('Validating Get Authorization Token API', (done) => { 80 | const configCopy = { ...config }; 81 | configCopy.sandbox = false; 82 | const amazonPayCLient = new Client.AmazonPayClient(configCopy); 83 | amazonPayCLient.getAuthorizationToken(mwsAuthToken, merchantId) 84 | .then(function (result) { 85 | var actualResponse = result.data; 86 | assert.ok(actualResponse.authorizationToken); 87 | done(); 88 | }) 89 | .catch(function (err) { 90 | done(err); 91 | }); 92 | }) 93 | 94 | it('Validating Get Authorization Token API with V2 Algorithm', (done) => { 95 | const configCopy = { ...configWithAlgorithm }; 96 | configCopy.sandbox = false; 97 | const amazonPayCLientWithAlgorithm = new Client.AmazonPayClient(configCopy); 98 | amazonPayCLientWithAlgorithm.getAuthorizationToken(mwsAuthToken, merchantId) 99 | .then(function (result) { 100 | var actualResponse = result.data; 101 | assert.ok(actualResponse.authorizationToken); 102 | done(); 103 | }) 104 | .catch(function (err) { 105 | done(err); 106 | }); 107 | }) 108 | }); 109 | 110 | -------------------------------------------------------------------------------- /tst/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | // Please Update the below mentioned values before running test cases 5 | 6 | const configArgs = { 7 | 'publicKeyId': '', // Enter your Public Key ID 8 | 'privateKey': fs.readFileSync('AmazonPay_publicKeyId.pem'), // Path to your private key file 9 | 'region': 'eu', 10 | 'sandbox': true, 11 | 'currencyCode': 'EUR', 12 | 'countryCode': 'DE', 13 | 'storeId': 'amzn1.application-oa2-client.xxxxxxxxx' 14 | }; 15 | 16 | module.exports = configArgs; 17 | -------------------------------------------------------------------------------- /tst/configWithAlgorithm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | // Please Update the below mentioned values before running test cases 5 | 6 | const configArgs = { 7 | 'publicKeyId': '', // Enter your Public Key ID 8 | 'privateKey': fs.readFileSync('AmazonPay_publicKeyId.pem'), // Path to your private key file 9 | 'region': 'eu', 10 | 'sandbox': true, 11 | 'currencyCode': 'EUR', 12 | 'countryCode': 'DE', 13 | 'storeId': 'amzn1.application-oa2-client.xxxxxxxxx', 14 | 'algorithm': 'AMZN-PAY-RSASSA-PSS-V2' 15 | }; 16 | 17 | module.exports = configArgs; 18 | -------------------------------------------------------------------------------- /tst/inStoreClientTest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Including Required Modules 4 | const Client = require('../src/client'); 5 | const config = require('./config'); 6 | const assert = require('assert'); 7 | const uuidv4 = require('uuid/v4'); 8 | const headers = { 9 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 10 | }; 11 | 12 | // Intiating InStoreClient Class 13 | const inStoreClient = new Client.InStoreClient(config); 14 | 15 | // Constants required to execute Unit Test cases 16 | var chargePermissionId; 17 | var chargeId; 18 | const merchantScanPayload = { 19 | scanData: "UKhrmatMeKdlfY6b", 20 | scanReferenceId: uuidv4().toString().replace(/-/g, ''), 21 | merchantCOE: config.countryCode, 22 | ledgerCurrency: config.currencyCode, 23 | storeLocation: { 24 | countryCode: config.countryCode 25 | }, 26 | metadata: { 27 | merchantNote: "Software Purchase", 28 | customInformation: "in-store Software Purchase", 29 | communicationContext: { 30 | merchantStoreName: "TESTSTORE", 31 | merchantOrderId: "789123" 32 | } 33 | } 34 | } 35 | const merchantScanExpectedResponse = { 36 | chargePermissionId: "" 37 | } 38 | const chargeExpectedResponse = { 39 | chargeId: "", 40 | chargeStatus: { 41 | state: "Completed" 42 | } 43 | } 44 | const refundExpectedResponse = { 45 | refundId: "", 46 | refundStatus: { 47 | state: "Pending" 48 | } 49 | } 50 | 51 | describe('InStore Client Test Cases', (done) => { 52 | 53 | it('Validating Merchant Scan API', (done) => { 54 | inStoreClient.merchantScan(merchantScanPayload).then(function (result) { 55 | var actualResponse = result.data; 56 | chargePermissionId = actualResponse.chargePermissionId; 57 | assert.deepStrictEqual(Object.keys(merchantScanExpectedResponse), Object.keys(actualResponse)); 58 | done(); 59 | }).catch(err => { 60 | done(err); 61 | }); 62 | }); 63 | 64 | it('Validating Charge API', (done) => { 65 | const chargePayload = { 66 | chargePermissionId: chargePermissionId, 67 | chargeReferenceId: uuidv4().toString().replace(/-/g, ''), 68 | chargeTotal: { 69 | currencyCode: config.currencyCode, 70 | amount: 2 71 | }, 72 | softDescriptor: "amzn-store" 73 | } 74 | inStoreClient.charge(chargePayload).then(function (result) { 75 | var actualResponse = result.data; 76 | chargeId = actualResponse.chargeId; 77 | assert.deepStrictEqual(Object.keys(chargeExpectedResponse), Object.keys(actualResponse)); 78 | done(); 79 | }).catch(err => { 80 | done(err); 81 | }); 82 | }); 83 | 84 | it('Validating Refund API', (done) => { 85 | const refundPayload = { 86 | chargeId: chargeId, 87 | refundReferenceId: uuidv4().toString().replace(/-/g, ''), 88 | refundTotal: { 89 | currencyCode: config.currencyCode, 90 | amount: 2 91 | }, 92 | softDescriptor: "amzn-store" 93 | } 94 | inStoreClient.refund(refundPayload).then(function (result) { 95 | var actualResponse = result.data; 96 | assert.deepStrictEqual(Object.keys(refundExpectedResponse), Object.keys(actualResponse)); 97 | done(); 98 | }).catch(err => { 99 | done(err); 100 | }); 101 | }); 102 | }); 103 | -------------------------------------------------------------------------------- /tst/unit/clientHelperTest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Including Required Modules 4 | const helper = require('../../src/clientHelper'); 5 | const constants = require('../../src/constants'); 6 | const assert = require('assert'); 7 | 8 | // Constants 9 | const expectedLiveURI = 'live/v2/serviceName'; 10 | const expectedSandboxURI = 'sandbox/v2/serviceName'; 11 | const expectedUnfiedURI = 'v2/serviceName'; 12 | 13 | // Test cases to validate Environment specific URI 14 | describe('Test Environment specific URI Test cases', () => { 15 | 16 | // Test to validate URI for Live specific URI 17 | it('Testing Live specific URI', (done) => { 18 | const response = helper.prepareOptions(getPayConfig(false), { urlFragment: 'serviceName' }); 19 | assert.strictEqual(response.urlFragment, expectedLiveURI); 20 | 21 | //Test with V2 Algorithm passed in config 22 | const responseWithAlgorithm = helper.prepareOptions(getPayConfig(false, constants.AMAZON_SIGNATURE_ALGORITHM.V2), { urlFragment: 'serviceName' }); 23 | assert.strictEqual(responseWithAlgorithm.urlFragment, expectedLiveURI); 24 | 25 | done(); 26 | }); 27 | 28 | // Test to validate URI for Sandbox specific URI 29 | it('Testing Sandbox specific URI', (done) => { 30 | const response = helper.prepareOptions(getPayConfig(true), { urlFragment: 'serviceName' }); 31 | assert.strictEqual(response.urlFragment, expectedSandboxURI); 32 | 33 | //Test with V2 Algorithm passed in config 34 | const responseWithAlgorithm = helper.prepareOptions(getPayConfig(true, constants.AMAZON_SIGNATURE_ALGORITHM.V2), { urlFragment: 'serviceName' }); 35 | assert.strictEqual(responseWithAlgorithm.urlFragment, expectedSandboxURI); 36 | 37 | done(); 38 | }); 39 | 40 | // Generic method used to create Pay Configuration 41 | function getPayConfig(sandboxFlag, algorithmPassed = null) { 42 | let payConfig = { 43 | 'publicKeyId': 'XXXXXXXXXXXXXXXXXXXXXXXX', 44 | 'privateKey': 'keys/private.pem', 45 | 'sandbox': sandboxFlag, 46 | 'region': 'us', 47 | }; 48 | 49 | if (algorithmPassed) { 50 | payConfig['algorithm'] = algorithmPassed; 51 | } 52 | return payConfig; 53 | } 54 | }); 55 | 56 | // Test cases to validate Unified Endpoint specific URI 57 | describe('Test Environment specific URI Test cases', () => { 58 | 59 | // Testing Unified endpoint URI by passing Live specific PublicKeyId 60 | it('Testing Unified endpoint URI for Live PublicKeyId', (done) => { 61 | const options = { urlFragment: 'serviceName' }; 62 | const response = helper.prepareOptions(getPayConfig('LIVE-XXXXXXXXXXXXXXXXXXXXXXXX'), { urlFragment: 'serviceName' }); 63 | assert.strictEqual(response.urlFragment, expectedUnfiedURI); 64 | 65 | //Test with V2 Algorithm passed in config 66 | const responseWithAlgorithm = helper.prepareOptions(getPayConfig('LIVE-XXXXXXXXXXXXXXXXXXXXXXXX', constants.AMAZON_SIGNATURE_ALGORITHM.V2), { urlFragment: 'serviceName' }); 67 | assert.strictEqual(responseWithAlgorithm.urlFragment, expectedUnfiedURI); 68 | done(); 69 | }); 70 | 71 | // Testing Unified endpoint URI by passing Sandbox specific PublicKeyId 72 | it('Testing Unified endpoint URI for Sandbox PublicKeyId', (done) => { 73 | const options = { urlFragment: 'serviceName' }; 74 | const response = helper.prepareOptions(getPayConfig('SANDBOX-XXXXXXXXXXXXXXXXXXXXXXXX'), { urlFragment: 'serviceName' }); 75 | assert.strictEqual(response.urlFragment, expectedUnfiedURI); 76 | 77 | //Test with V2 Algorithm passed in config 78 | const responseWithAlgorithm = helper.prepareOptions(getPayConfig('SANDBOX-XXXXXXXXXXXXXXXXXXXXXXXX', constants.AMAZON_SIGNATURE_ALGORITHM.V2), { urlFragment: 'serviceName' }); 79 | assert.strictEqual(responseWithAlgorithm.urlFragment, expectedUnfiedURI); 80 | 81 | done(); 82 | }); 83 | 84 | // Generic method used to create Pay Configuration 85 | function getPayConfig(publicKeyId, algorithmPassed = null) { 86 | let payConfig = { 87 | 'publicKeyId': publicKeyId, 88 | 'privateKey': 'keys/private.pem', 89 | 'region': 'us', 90 | }; 91 | 92 | if (algorithmPassed) { 93 | payConfig['algorithm'] = algorithmPassed; 94 | } 95 | return payConfig; 96 | } 97 | }); -------------------------------------------------------------------------------- /tst/webStoreClientTest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Including Required Modules 4 | const Client = require('../src/client'); 5 | const config = require('./config'); 6 | const configWithAlgorithm = require('./configWithAlgorithm'); 7 | const assert = require('assert'); 8 | const uuidv4 = require('uuid/v4'); 9 | const headers = { 10 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 11 | }; 12 | const headersWithV2Algorithm = { 13 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 14 | }; 15 | 16 | const chargePermissionId = ''; // Enter Charge Permission ID 17 | const chargePermissionIdWithV2Algorithm = ''; // Enter Charge Permission ID 18 | const buyerToken = ''; // Enter Buyer Token 19 | const buyerTokenWithV2Algorithm = ''; // Enter Buyer Token 20 | const finalizeCheckoutSessionId = ''; // Enter Chechout Session Id for SPC flow 21 | const finalizeCheckoutSessionIdWithV2Algorithm = ''; // Enter Chechout Session Id for SPC flow 22 | const pspChargeId=''; // Enter PSP Charge ID for updateCharge API 23 | const pspChargeIdWithV2Algorithm=''; // Enter PSP Charge ID for updateCharge API 24 | 25 | // Initiating WebStoreClient Class 26 | const webStoreClient = new Client.WebStoreClient(config); 27 | const webStoreClientWithAlgorithm = new Client.WebStoreClient(configWithAlgorithm); 28 | 29 | // Constants required to execute Unit Test cases 30 | var checkoutSessionId; 31 | var chargeId; 32 | var chargeIdWithV2Algorithm; 33 | var refundId; 34 | var merchantAccountId; 35 | var reportScheduleId; 36 | var disputeId; 37 | 38 | const createCheckoutSessionPayload = { 39 | webCheckoutDetails: { 40 | checkoutReviewReturnUrl: 'https://localhost/maxo/checkoutReview.html', 41 | checkoutResultReturnUrl: 'https://localhost/maxo/checkoutReturn.html' 42 | }, 43 | storeId: config.storeId // Enter Store ID 44 | }; 45 | const updateCheckoutSessionPayload = { 46 | paymentDetails: { 47 | paymentIntent: 'Confirm', 48 | chargeAmount: { 49 | amount: 50, 50 | currencyCode: config.currencyCode 51 | } 52 | }, 53 | merchantMetadata: { 54 | merchantReferenceId: uuidv4().toString().replace(/-/g, ''), 55 | merchantStoreName: 'Test Shop EU', 56 | noteToBuyer: 'Thank you for your order!' 57 | } 58 | }; 59 | const completeCheckoutSessionPayload = { 60 | chargeAmount: { 61 | amount: 50, 62 | currencyCode: config.currencyCode 63 | } 64 | } 65 | const finalizeCheckoutSessionPayload = { 66 | shippingAddress: { 67 | name: "Susie Smith", 68 | addressLine1: "10 Ditka Ave", 69 | addressLine2: "Suite 2500", 70 | city: "Chicago", 71 | county: null, 72 | district: null, 73 | stateOrRegion: "IL", 74 | postalCode: "60602", 75 | countryCode: "US", 76 | phoneNumber: "800-000-0000" 77 | }, 78 | billingAddress: null, 79 | chargeAmount: { 80 | amount: "10", 81 | currencyCode: "USD" 82 | }, 83 | totalOrderAmount: { 84 | amount: "10", 85 | currencyCode: "USD" 86 | }, 87 | paymentIntent: "Confirm", 88 | canHandlePendingAuthorization: false, 89 | supplementaryData: "TestSupplementaryData-onInitCheckout" 90 | }; 91 | const updateChargePermissionPayload = { 92 | merchantMetadata: { 93 | merchantReferenceId: uuidv4().toString().replace(/-/g, ''), 94 | merchantStoreName: 'Test Shop EU', 95 | noteToBuyer: 'Thank you for your order!', 96 | customInformation: 'Custom Info' 97 | } 98 | }; 99 | const closeChargePermissionPayload = { 100 | closureReason: 'All actions completed', 101 | cancelPendingCharges: false 102 | }; 103 | const createChargePayload = { 104 | chargePermissionId: chargePermissionId, 105 | chargeAmount: { 106 | amount: '0.01', 107 | currencyCode: config.currencyCode 108 | }, 109 | captureNow: false, 110 | canHandlePendingAuthorization: false 111 | }; 112 | const createChargePayloadWithV2Algorithm = { 113 | chargePermissionId: chargePermissionIdWithV2Algorithm, 114 | chargeAmount: { 115 | amount: '0.01', 116 | currencyCode: config.currencyCode 117 | }, 118 | captureNow: false, 119 | canHandlePendingAuthorization: false 120 | }; 121 | 122 | const captureChargePayload = { 123 | captureAmount: { 124 | amount: '0.01', 125 | currencyCode: config.currencyCode 126 | }, 127 | softDescriptor: 'AMZN' 128 | } 129 | const cancelChargePayload = { 130 | cancellationReason: 'Cancelling Charge Test' 131 | }; 132 | 133 | const createIndividualBusinessPayload = { 134 | uniqueReferenceId: 'ABCD12345CB', 135 | ledgerCurrency: 'JPY', 136 | businessInfo: { 137 | businessType: 'INDIVIDUAL', 138 | countryOfEstablishment: 'JP', 139 | businessLegalName: 'TestingSubmerchant', 140 | businessAddress: { 141 | addressLine1: '450 Noda', 142 | city: '香取市', 143 | stateOrRegion: '千葉県', 144 | postalCode: '289-0314', 145 | countryCode: 'JP' 146 | } 147 | } 148 | }; 149 | 150 | const createCorporateBusinessPayload = { 151 | uniqueReferenceId: 'ABCD12345CB', 152 | ledgerCurrency: 'JPY', 153 | businessInfo: { 154 | businessType: 'CORPORATE', 155 | countryOfEstablishment: 'JP', 156 | businessLegalName: 'TestingSubmerchant', 157 | businessAddress: { 158 | addressLine1: '450', 159 | addressLine2: 'Noda', 160 | city: '香取市', 161 | stateOrRegion: '千葉県', 162 | postalCode: '289-0314', 163 | countryCode: 'JP' 164 | } 165 | }, 166 | primaryContactPerson: { 167 | personFullName: 'Integration Tests', 168 | residentialAddress: { 169 | addressLine1: '4-7, Sunny Mansion 203', 170 | addressLine2: 'Hommachi 2 choume', 171 | city: 'Chiryushi', 172 | stateOrRegion: 'AICHI', 173 | postalCode: '4720021', 174 | countryCode: 'JP' 175 | } 176 | } 177 | }; 178 | 179 | const createCorporateWithoutPocPayload = { 180 | uniqueReferenceId: 'ABCD12345CB', 181 | ledgerCurrency: 'JPY', 182 | businessInfo: { 183 | businessType: 'CORPORATE', 184 | countryOfEstablishment: 'JP', 185 | businessLegalName: 'TestingSubmerchant', 186 | businessAddress: { 187 | addressLine1: '450', 188 | addressLine2: 'Noda', 189 | city: '香取市', 190 | stateOrRegion: '千葉県', 191 | postalCode: '289-0314', 192 | countryCode: 'JP' 193 | } 194 | } 195 | }; 196 | 197 | const createUpdatePayload = { 198 | businessInfo: { 199 | businessAddress: { 200 | addressLine1: '41 Nishigamo Kitaimaharacho', 201 | city: '京都市', 202 | stateOrRegion: '京都府', 203 | postalCode: '603-8821', 204 | countryCode: 'JP' 205 | } 206 | } 207 | }; 208 | 209 | const updateChargePayload= { 210 | "statusDetails": { 211 | "state": "Canceled", 212 | "reasonCode": "ExpiredUnused" 213 | } 214 | }; 215 | 216 | const updateChargePayloadWithV2Algorithm= { 217 | "statusDetails": { 218 | "state": "Canceled", 219 | "reasonCode": "ExpiredUnused" 220 | } 221 | }; 222 | 223 | const createDisputePayload={ 224 | 'chargeId': pspChargeId, 225 | 'providerMetadata': { 226 | 'providerDisputeId': 'A2CQXQ2TUSYG7J' 227 | }, 228 | 'disputeAmount': { 229 | 'amount': '1', 230 | 'currencyCode': configWithAlgorithm.currencyCode 231 | }, 232 | 'filingReason': 'ProductNotReceived', 233 | 'filingTimestamp': Date.now(), 234 | 'statusDetails': { 235 | 'state': 'ActionRequired' 236 | }, 237 | 'merchantResponseDeadline': Date.now()+ (14 * 24 * 60 * 60 * 1000) 238 | }; 239 | 240 | const updateDisputePayload={ 241 | "statusDetails": { 242 | "resolution": "MerchantWon", 243 | "state": "Resolved", 244 | "reasonCode": "MerchantAcceptedDispute", 245 | "reasonDescription": "Merchant accepted the dispute request" 246 | }, 247 | "closureTimestamp": Date.now() 248 | }; 249 | 250 | const contestDisputePayload= { 251 | "merchantEvidences": [ 252 | { 253 | "evidenceType" : "TrackingNumber", 254 | "fileId": "ababcbchdhdhhduathcfjhf", 255 | "evidenceText": "raw text supporting merchant evidence" 256 | } 257 | ] 258 | } 259 | 260 | const uploadFilePayload = { 261 | "type" : "jpg", 262 | "purpose" : "disputeEvidence" 263 | }; 264 | 265 | function validateGetBuyerResponse(result) { 266 | assert.strictEqual(result.status, 200); 267 | var actualResponse = result.data; 268 | assert.deepStrictEqual(actualResponse.buyerId.startsWith('amzn1.account.'), true); 269 | } 270 | 271 | // Validating Checkout Session API Calls 272 | describe('WebStore Client Test Cases - Checkout Session APIs', () => { 273 | before(function () { 274 | if (!createCheckoutSessionPayload.storeId) { 275 | console.error('Please provide storeId in the payload before executing these test cases'); 276 | this.skip(); 277 | } 278 | }); 279 | 280 | const expectedResponse = { 281 | checkoutSessionId: '', 282 | webCheckoutDetails: '', 283 | productType: '', 284 | paymentDetails: '', 285 | chargePermissionType: '', 286 | orderType: '', 287 | recurringMetadata: '', 288 | paymentMethodOnFileMetadata: '', 289 | merchantDetails: '', 290 | merchantMetadata: '', 291 | supplementaryData: '', 292 | buyer: '', 293 | billingAddress: '', 294 | paymentPreferences: '', 295 | statusDetails: '', 296 | shippingAddress: '', 297 | platformId: '', 298 | chargePermissionId: '', 299 | chargeId: '', 300 | constraints: '', 301 | creationTimestamp: '', 302 | expirationTimestamp: '', 303 | storeId: '', 304 | providerMetadata: '', 305 | releaseEnvironment: '', 306 | checkoutButtonText: '', 307 | deliverySpecifications: '', 308 | tokens: '' 309 | }; 310 | 311 | it('Validating Get Buyer API', (done) => { 312 | webStoreClient.getBuyer(buyerToken, headers) 313 | .then(validateGetBuyerResponse) 314 | .then(done) 315 | .catch(done); 316 | }); 317 | 318 | it('Validating Get Buyer API with V2 Algorithm', (done) => { 319 | webStoreClientWithAlgorithm.getBuyer(buyerTokenWithV2Algorithm, headersWithV2Algorithm) 320 | .then(validateGetBuyerResponse) 321 | .then(done) 322 | .catch(done); 323 | }); 324 | 325 | function validateCreateCheckoutSessionResponse(result) { 326 | assert.strictEqual(result.status, 201); 327 | var actualResponse = result.data; 328 | checkoutSessionId = actualResponse.checkoutSessionId; 329 | assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); 330 | } 331 | 332 | it('Validating Create Checkout Session API', (done) => { 333 | webStoreClient.createCheckoutSession(createCheckoutSessionPayload, headers) 334 | .then(validateCreateCheckoutSessionResponse) 335 | .then(done) 336 | .catch(done); 337 | }); 338 | 339 | it('Validating Create Checkout Session API with V2 Algorithm', (done) => { 340 | webStoreClientWithAlgorithm.createCheckoutSession(createCheckoutSessionPayload, headersWithV2Algorithm) 341 | .then(validateCreateCheckoutSessionResponse) 342 | .then(done) 343 | .catch(done); 344 | }); 345 | 346 | it('Validating Get Checkout Session API', (done) => { 347 | webStoreClient.getCheckoutSession(checkoutSessionId, headers) 348 | .then(validateCheckoutSessionResponse) 349 | .then(done) 350 | .catch(done); 351 | }); 352 | 353 | it('Validating Get Checkout Session API with V2 Algorithm', (done) => { 354 | webStoreClientWithAlgorithm.getCheckoutSession(checkoutSessionId, headersWithV2Algorithm) 355 | .then(validateCheckoutSessionResponse) 356 | .then(done) 357 | .catch(done); 358 | }); 359 | 360 | it('Validating Update Checkout Session API', (done) => { 361 | webStoreClient.updateCheckoutSession(checkoutSessionId, updateCheckoutSessionPayload) 362 | .then(validateCheckoutSessionResponse) 363 | .then(done) 364 | .catch(done); 365 | }); 366 | 367 | it('Validating Update Checkout Session API with V2 Algorithm', (done) => { 368 | webStoreClientWithAlgorithm.updateCheckoutSession(checkoutSessionId, updateCheckoutSessionPayload) 369 | .then(validateCheckoutSessionResponse) 370 | .then(done) 371 | .catch(done); 372 | }); 373 | 374 | // Can only run this after visiting amazonPayRedirectUrl 375 | it.skip('Validating Complete Checkout Session API', (done) => { 376 | webStoreClient.completeCheckoutSession(checkoutSessionId, completeCheckoutSessionPayload) 377 | .then(validateCheckoutSessionResponse) 378 | .then(done) 379 | .catch(done); 380 | }); 381 | 382 | // Can only run this after visiting amazonPayRedirectUrl 383 | it.skip('Validating Complete Checkout Session API With V2 Algorithm', (done) => { 384 | webStoreClient.completeCheckoutSession(checkoutSessionId, completeCheckoutSessionPayload) 385 | .then(validateCheckoutSessionResponse) 386 | .then(done) 387 | .catch(done); 388 | }); 389 | 390 | function validateCheckoutSessionResponse(result) { 391 | assert.strictEqual(result.status, 200); 392 | var actualResponse = result.data; 393 | assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); 394 | } 395 | }); 396 | 397 | describe('WebStore Client Test Cases - Finalize Checkout Session APIs', () => { 398 | before(function () { 399 | if (!finalizeCheckoutSessionId && !finalizeCheckoutSessionIdWithV2Algorithm) { 400 | console.error('Please provide finalize checkout session id before executing these test cases'); 401 | this.skip(); 402 | } 403 | }); 404 | 405 | const expectedResponse = { 406 | checkoutSessionId: '', 407 | webCheckoutDetails: '', 408 | productType: '', 409 | paymentDetails: '', 410 | cartDetails: '', 411 | chargePermissionType: '', 412 | orderType: '', 413 | recurringMetadata: '', 414 | paymentMethodOnFileMetadata: '', 415 | merchantDetails: '', 416 | merchantMetadata: '', 417 | supplementaryData: '', 418 | buyer: '', 419 | billingAddress: '', 420 | paymentPreferences: '', 421 | statusDetails: '', 422 | shippingAddress: '', 423 | platformId: '', 424 | chargePermissionId: '', 425 | chargeId: '', 426 | constraints: '', 427 | creationTimestamp: '', 428 | expirationTimestamp: '', 429 | storeId: '', 430 | providerMetadata: '', 431 | releaseEnvironment: '', 432 | checkoutButtonText: '', 433 | deliverySpecifications: '', 434 | tokens: '' 435 | }; 436 | 437 | function validateCheckoutSessionResponse(result) { 438 | assert.strictEqual(result.status, 200); 439 | var actualResponse = result.data; 440 | assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); 441 | } 442 | 443 | // Test for finalizeCheckoutSession with V1 Algorithm 444 | it('Validating Finalize Checkout Session API', (done) => { 445 | webStoreClient.finalizeCheckoutSession(finalizeCheckoutSessionId, finalizeCheckoutSessionPayload) 446 | .then(validateCheckoutSessionResponse) 447 | .then(done) 448 | .catch(done); 449 | }); 450 | 451 | // Test for finalizeCheckoutSession with V2 Algorithm 452 | it('Validating Finalize Checkout Session API With V2 Algorithm', (done) => { 453 | webStoreClient.finalizeCheckoutSession(finalizeCheckoutSessionIdWithV2Algorithm, finalizeCheckoutSessionPayload) 454 | .then(validateCheckoutSessionResponse) 455 | .then(done) 456 | .catch(done); 457 | }); 458 | }); 459 | 460 | describe('', () => { 461 | // Skip the tests if chargePermissionId is not provided 462 | before(function () { 463 | if (!chargePermissionId && !chargePermissionIdWithV2Algorithm) { 464 | console.error('Please provide chargePermissionId before executing these test cases'); 465 | this.skip(); 466 | } 467 | }); 468 | 469 | // Validating Charge Permission API Call's 470 | describe('WebStore Client Test Cases - Charge Permission APIs', (done) => { 471 | const expectedResponseKeys = ['chargePermissionId', 'chargePermissionReferenceId:', 'platformId', 'buyer', 'shippingAddress', 'billingAddress', 'paymentPreferences', 'statusDetails', 'creationTimestamp', 'expirationTimestamp', 'merchantMetadata', 'releaseEnvironment', 'limits', 'chargePermissionType', 'recurringMetadata', 'presentmentCurrency']; 472 | 473 | function validateChargePermissionResponse(result) { 474 | assert.strictEqual(result.status, 200); 475 | var actualResponse = result.data; 476 | expectedResponseKeys.forEach(key => { 477 | assert.ok(actualResponse.hasOwnProperty(key), `Missing key: ${key}`); 478 | }); 479 | } 480 | 481 | it('Validating Get Charge Permission API', (done) => { 482 | webStoreClient.getChargePermission(chargePermissionId, headers) 483 | .then(validateChargePermissionResponse) 484 | .then(done) 485 | .catch(done); 486 | }); 487 | 488 | it('Validating Get Charge Permission API with V2 Algorithm', (done) => { 489 | webStoreClientWithAlgorithm.getChargePermission(chargePermissionIdWithV2Algorithm, headersWithV2Algorithm) 490 | .then(validateChargePermissionResponse) 491 | .then(done) 492 | .catch(done); 493 | }); 494 | 495 | it('Validating Update Charge Permission API', (done) => { 496 | webStoreClient.updateChargePermission(chargePermissionId, updateChargePermissionPayload, headers) 497 | .then(validateChargePermissionResponse) 498 | .then(done) 499 | .catch(done); 500 | }); 501 | 502 | it('Validating Update Charge Permission API with V2 Algorithm', (done) => { 503 | webStoreClientWithAlgorithm.updateChargePermission(chargePermissionIdWithV2Algorithm, updateChargePermissionPayload, headersWithV2Algorithm) 504 | .then(validateChargePermissionResponse) 505 | .then(done) 506 | .catch(done); 507 | }); 508 | 509 | // Cannot Create Charge if Close Charge Permission is executed, unskip this test case and skip Charge API Tests to validate this API 510 | it.skip('Validating Close Charge Permission API', (done) => { 511 | webStoreClient.closeChargePermission(chargePermissionId, closeChargePermissionPayload, headers) 512 | .then(validateChargePermissionResponse) 513 | .then(done) 514 | .catch(done); 515 | }); 516 | 517 | it.skip('Validating Close Charge Permission API with V2 Algorithm', (done) => { 518 | webStoreClient.closeChargePermission(chargePermissionIdWithV2Algorithm, closeChargePermissionPayload, headersWithV2Algorithm) 519 | .then(validateChargePermissionResponse) 520 | .then(done) 521 | .catch(done); 522 | }); 523 | }); 524 | 525 | // Validating Create Charge API Call 526 | describe('WebStore Client Test Cases - Charge APIs', (done) => { 527 | const expectedResponseKeys = ['chargeId', 'chargeAmount', 'chargePermissionId', 'captureAmount', 'refundedAmount', 'softDescriptor', 'providerMetadata', 'convertedAmount', 'conversionRate', 'channel', 'chargeInitiator', 'statusDetails', 'creationTimestamp', 'expirationTimestamp', 'releaseEnvironment', 'merchantMetadata', 'platformId', 'webCheckoutDetails']; 528 | 529 | before(function () { 530 | if (!chargePermissionId && !chargePermissionIdWithV2Algorithm) { 531 | console.error('Please Enter chargePermissionId and execute test cases'); 532 | this.skip(); 533 | } 534 | }); 535 | 536 | function validateCreateChargeResponse(result) { 537 | assert.strictEqual(result.status, 201); 538 | var actualResponse = result.data; 539 | chargeId = actualResponse.chargeId; 540 | expectedResponseKeys.forEach(key => { 541 | assert.ok(actualResponse.hasOwnProperty(key), `Missing key: ${key}`); 542 | }); 543 | } 544 | 545 | it('Validating Create Charge API', (done) => { 546 | webStoreClient.createCharge(createChargePayload, headers) 547 | .then(validateCreateChargeResponse) 548 | .then(done) 549 | .catch(done); 550 | }); 551 | 552 | it('Validating Create Charge API with V2 Algorithm', (done) => { 553 | webStoreClientWithAlgorithm.createCharge(createChargePayloadWithV2Algorithm, headersWithV2Algorithm) 554 | .then(validateCreateChargeResponse) 555 | .then(done) 556 | .catch(done); 557 | }); 558 | 559 | function validateChargeResponse(result) { 560 | assert.strictEqual(result.status, 200); 561 | var actualResponse = result.data; 562 | expectedResponseKeys.forEach(key => { 563 | assert.ok(actualResponse.hasOwnProperty(key), `Missing key: ${key}`); 564 | }); 565 | } 566 | 567 | it('Validating Get Charge API', (done) => { 568 | webStoreClient.getCharge(chargeId, headers) 569 | .then(validateChargeResponse) 570 | .then(done) 571 | .catch(done); 572 | }); 573 | 574 | it('Validating Get Charge API with V2 Algorithm', (done) => { 575 | webStoreClientWithAlgorithm.getCharge(chargeId, headersWithV2Algorithm) 576 | .then(validateChargeResponse) 577 | .then(done) 578 | .catch(done); 579 | }); 580 | 581 | it('Validating Update Charge API', (done) => { 582 | webStoreClient.updateCharge(pspChargeId, updateChargePayload, headers) 583 | .then(validateChargeResponse) 584 | .then(done) 585 | .catch(done); 586 | }); 587 | 588 | it('Validating Update Charge API with V2 Algorithm', (done) => { 589 | webStoreClientWithAlgorithm.updateCharge(pspChargeIdWithV2Algorithm, updateChargePayloadWithV2Algorithm, headersWithV2Algorithm) 590 | .then(validateChargeResponse) 591 | .then(done) 592 | .catch(done); 593 | }); 594 | 595 | it('Validating Capture Charge API', (done) => { 596 | webStoreClient.captureCharge(chargeId, captureChargePayload, headers) 597 | .then(validateChargeResponse) 598 | .then(done) 599 | .catch(done); 600 | }); 601 | 602 | it('Validating Capture Charge API with V2 Algorithm', (done) => { 603 | webStoreClientWithAlgorithm.captureCharge(chargeId, captureChargePayload, headers) 604 | .then(validateChargeResponse) 605 | .then(done) 606 | .catch(done); 607 | }); 608 | 609 | // Cannot Run both Capture charge and Cancel charge at same time, Run either Capture Capture or Cancel Charge 610 | it.skip('Validating Cancel Charge API', (done) => { 611 | webStoreClient.cancelCharge(chargeId, cancelChargePayload, headers) 612 | .then(validateChargeResponse) 613 | .then(done) 614 | .catch(done); 615 | }); 616 | 617 | // Cannot Run both Capture charge and Cancel charge at same time, Run either Capture Capture or Cancel Charge 618 | it.skip('Validating Cancel Charge API with V2 Algorithm', (done) => { 619 | webStoreClientWithAlgorithm.cancelCharge(chargeIdWithV2Algorithm, cancelChargePayload, headersWithV2Algorithm) 620 | .then(validateChargeResponse) 621 | .then(done) 622 | .catch(done); 623 | }); 624 | }); 625 | 626 | //Validating Refund API Call's 627 | describe('WebStore Client Test Cases - Refund APIs', (done) => { 628 | // Refund API should have different idempotency key, Hence creating new headers 629 | const headers = { 630 | 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') 631 | }; 632 | const expectedResponseKeys = ['refundId', 'chargeId', 'creationTimestamp', 'refundAmount', 'statusDetails', 'softDescriptor', 'releaseEnvironment']; 633 | 634 | before(function () { 635 | if (!chargePermissionId && !chargePermissionIdWithV2Algorithm) { 636 | console.error('Please Enter chargePermissionId and execute test cases'); 637 | this.skip(); 638 | } 639 | }); 640 | 641 | function validatCreateRefundResponse(result) { 642 | assert.strictEqual(result.status, 201); 643 | var actualResponse = result.data; 644 | refundId = actualResponse.refundId; 645 | expectedResponseKeys.forEach(key => { 646 | assert.ok(actualResponse.hasOwnProperty(key), `Missing key: ${key}`); 647 | }); 648 | } 649 | 650 | it('Validating Create Refund API', (done) => { 651 | const refundPayload = { 652 | chargeId: chargeId, 653 | refundAmount: { 654 | amount: '0.01', 655 | currencyCode: config.currencyCode 656 | }, 657 | softDescriptor: 'SOFT_DESCRIPTOR' 658 | }; 659 | webStoreClient.createRefund(refundPayload, headers) 660 | .then(validatCreateRefundResponse) 661 | .then(done) 662 | .catch(done); 663 | }); 664 | 665 | it('Validating Create Refund API with V2 Algorithm', (done) => { 666 | const refundPayload = { 667 | chargeId: chargeId, 668 | refundAmount: { 669 | amount: '0.01', 670 | currencyCode: config.currencyCode 671 | }, 672 | softDescriptor: 'SOFT_DESCRIPTOR' 673 | }; 674 | webStoreClientWithAlgorithm.createRefund(refundPayload, headers) 675 | .then(validatCreateRefundResponse) 676 | .then(done) 677 | .catch(done); 678 | }); 679 | 680 | function validatGetRefundResponse(result) { 681 | assert.strictEqual(result.status, 200); 682 | var actualResponse = result.data; 683 | Object.keys(expectedResponse).forEach(key => { 684 | assert.ok(actualResponse.hasOwnProperty(key), `Missing key: ${key}`); 685 | }); 686 | } 687 | 688 | it('Validating Get Refund API', (done) => { 689 | webStoreClient.getRefund(refundId, headers) 690 | .then(validatGetRefundResponse) 691 | .then(done) 692 | .catch(done); 693 | }); 694 | 695 | it('Validating Get Refund API with V2 Algorithm', (done) => { 696 | webStoreClientWithAlgorithm.getRefund(refundId, headers) 697 | .then(validatGetRefundResponse) 698 | .then(done) 699 | .catch(done); 700 | }); 701 | }); 702 | 703 | 704 | // ------------ Testing the CV2 Reporting APIs --------------- 705 | describe('WebStore Client Test Cases - CV2 Reporting APIs', (done) => { 706 | const startTime = '20230618T150630Z'; 707 | const endTime = '20230911T150350Z'; 708 | 709 | const expectGetReportResponse = { 710 | createdTime: '', 711 | endTime: '', 712 | processingEndTime: '', 713 | processingStartTime: '', 714 | processingStatus: '', 715 | reportDocumentId: '', 716 | reportId: '', 717 | reportType: '', 718 | startTime: '' 719 | } 720 | 721 | const expectGetReportSchedulesReponse = { 722 | nextReportCreationTime: '', 723 | reportScheduleId: '', 724 | reportType: '', 725 | scheduleFrequency: '', 726 | } 727 | 728 | // Tests the GetReports API 729 | it('Validating Get Report API', (done) => { 730 | const requestPayload = { 731 | 'reportType': '', 732 | 'processingStatus': '', 733 | 'createdSince': startTime, 734 | 'createdUntil': endTime, 735 | 'pageSize': '10' 736 | } 737 | webStoreClient.getReports().then(function (result) { 738 | assert.strictEqual(result.status, 200); 739 | var response = result.data; 740 | var reports = response['reports']; 741 | assert.deepStrictEqual(Object.keys(expectGetReportResponse), Object.keys(reports[0])); 742 | done(); 743 | }).catch(err => { 744 | done(err); 745 | }); 746 | }); 747 | 748 | // Tests the GetReportById API 749 | it('Validating Get Report By Id API', (done) => { 750 | const reportId = '59007019641'; 751 | webStoreClient.getReportById(reportId, headers).then(function (result) { 752 | assert.strictEqual(result.status, 200); 753 | var response = result.data; 754 | assert.deepStrictEqual(Object.keys(expectGetReportResponse), Object.keys(response)); 755 | done(); 756 | }).catch(err => { 757 | done(err); 758 | }); 759 | }); 760 | 761 | // Cannot test GerReportDocument right now, as it deals with Settlement reports which are not supported in our accounts 762 | // Tests Get Report Document API 763 | // it('Validating Get Report Document API', (done) => { 764 | // const reportDocumentId = '61516019327'; 765 | // webStoreClient.getReportDocument(reportDocumentId, headers).then(function (result) { 766 | // assert.strictEqual(result.status, 200); 767 | // var response = result.data; 768 | // assert.deepStrictEqual(Object.keys(expectGetReportResponse), Object.keys(response)); 769 | // done(); 770 | // }).catch(err => { 771 | // done(err); 772 | // }); 773 | // }); 774 | 775 | // Tests Get Report Schedules API 776 | it('Validating Create Report Schedule API', (done) => { 777 | const requestPayload = { 778 | 'reportType': '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_AUTHORIZATION_DATA_', 779 | 'scheduleFrequency': 'PT84H', 780 | 'nextReportCreationTime': startTime, 781 | 'deleteExistingSchedule': true 782 | } 783 | webStoreClient.createReportSchedule(requestPayload, headers).then(function (result) { 784 | assert.strictEqual(result.status, 201); 785 | var response = result.data; 786 | reportScheduleId = response['reportScheduleId']; 787 | done(); 788 | }).catch(err => { 789 | done(err); 790 | }); 791 | }); 792 | 793 | it('Validating Get Report Schedules API', (done) => { 794 | const reportTypes = '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_AUTHORIZATION_DATA_,_GET_FLAT_FILE_OFFAMAZONPAYMENTS_BILLING_AGREEMENT_DATA_'; 795 | webStoreClient.getReportSchedules(reportTypes, headers).then(function (result) { 796 | assert.strictEqual(result.status, 200); 797 | var response = result.data; 798 | var reportSchedules = response['reportSchedules']; 799 | assert.deepStrictEqual(Object.keys(expectGetReportSchedulesReponse), Object.keys(reportSchedules[0])); 800 | done(); 801 | }).catch(err => { 802 | done(err); 803 | }); 804 | }); 805 | 806 | // Tests Get Report Schedule by Id API 807 | it('Validating Get Report Schedule by Id API', (done) => { 808 | webStoreClient.getReportScheduleById(reportScheduleId, headers).then(function (result) { 809 | assert.strictEqual(result.status, 200); 810 | var response = result.data; 811 | assert.deepStrictEqual(Object.keys(expectGetReportSchedulesReponse), Object.keys(response)); 812 | done(); 813 | }).catch(err => { 814 | done(err); 815 | }); 816 | }); 817 | 818 | // Tests Create Report API 819 | it('Validating Create Report API', (done) => { 820 | const requestPayload = { 821 | 'reportType': '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_AUTHORIZATION_DATA_', 822 | 'startTime': startTime, 823 | 'endTime': endTime 824 | } 825 | webStoreClient.createReport(requestPayload, headers).then(function (result) { 826 | assert.strictEqual(result.status, 201); 827 | var response = result.data; 828 | var reportId = response['reportId']; 829 | assert.ok(reportId !== null); 830 | done(); 831 | }).catch(err => { 832 | done(err); 833 | }); 834 | }); 835 | 836 | // Tests Create and Cancel ReportSchedule API 837 | it('Validating Create Report Schedule API and Cancel Report Schedule API', (done) => { 838 | const requestPayload = { 839 | 'reportType': '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_AUTHORIZATION_DATA_', 840 | 'scheduleFrequency': 'PT84H', 841 | 'nextReportCreationTime': startTime, 842 | 'deleteExistingSchedule': true 843 | } 844 | webStoreClient.createReportSchedule(requestPayload, headers).then(function (result) { 845 | assert.strictEqual(result.status, 201); 846 | var response = result.data; 847 | var reportScheduleId = response['reportScheduleId']; 848 | assert.ok(reportScheduleId !== null); 849 | 850 | webStoreClient.cancelReportSchedule(reportScheduleId).then(function (resuLt) { 851 | assert.strictEqual(resuLt.status, 200); 852 | }).catch(err => { 853 | done(err); 854 | }); 855 | 856 | done(); 857 | }).catch(err => { 858 | done(err); 859 | }); 860 | }); 861 | }); 862 | 863 | // ------------ Testing the Merchant Onboarding & Account Management APIs --------------- 864 | 865 | describe('WebStore Client Test Cases - Merchant Onboarding & Account Management APIs', (done) => { 866 | 867 | const expectedAmazonPayAccountResponse = { 868 | uniqueReferenceId: '', 869 | merchantAccountId: '' 870 | }; 871 | 872 | function validateRegisterAmazonPayResponse(result) { 873 | assert.strictEqual(result.status, 201); 874 | var actualResponse = result.data; 875 | merchantAccountId = actualResponse.merchantAccountId; 876 | assert.deepStrictEqual(Object.keys(expectedAmazonPayAccountResponse), Object.keys(actualResponse)); 877 | } 878 | 879 | function validateDeleteAmazonPayAccountResponse(result) { 880 | assert.strictEqual(result.status, 202); 881 | } 882 | 883 | function validateUpdateAmazonPayAccountResponse(result) { 884 | assert.strictEqual(result.status, 204); 885 | } 886 | 887 | // Validating Register, Update and Delete Amazon Pay Account APIs 888 | function amazonPayAccountOperations(payload) { 889 | return webStoreClient.registerAmazonPayAccount(payload, headers) 890 | .then(validateRegisterAmazonPayResponse) 891 | .then(() => webStoreClient.updateAmazonPayAccount(merchantAccountId, createUpdatePayload)) 892 | .then(validateUpdateAmazonPayAccountResponse) 893 | .then(() => webStoreClient.deleteAmazonPayAccount(merchantAccountId)) 894 | .then(validateDeleteAmazonPayAccountResponse); 895 | } 896 | 897 | const testAmazonPayAccountOperations = (payload, businessType) => { 898 | it(`Validating Register Amazon Pay Account API with ${businessType}`, (done) => { 899 | amazonPayAccountOperations(payload) 900 | .then(done) 901 | .catch(done); 902 | }); 903 | } 904 | 905 | testAmazonPayAccountOperations(createIndividualBusinessPayload, 'Individual Business Type'); 906 | testAmazonPayAccountOperations(createCorporateBusinessPayload, 'Corporate Business Type and with Poc'); 907 | testAmazonPayAccountOperations(createCorporateWithoutPocPayload, 'Corporate Business Type and without Poc'); 908 | }); 909 | 910 | // ------------ Testing the Disputes APIs --------------- 911 | 912 | describe('WebStore Client Test Cases - Disputes APIs', (done) => { 913 | 914 | before(function () { 915 | if (!pspChargeId && !pspChargeIdWithV2Algorithm) { 916 | console.error('Please provide PSP chargeId before executing these test cases'); 917 | this.skip(); 918 | } 919 | }); 920 | 921 | const expectedDisputeResponseKeys =['disputeId', 'chargeId', 'disputeType', 'disputeAmount', 'filingReason', 'resolutionAuthority', 'statusDetails', 'merchantResponseDeadline', 'releaseEnvironment']; 922 | 923 | function validateDisputeAPIResponse(result) { 924 | assert.strictEqual(result.status, 200); 925 | var actualResponse = result.data; 926 | disputeId=actualResponse.disputeId 927 | expectedDisputeResponseKeys.forEach(key => { 928 | assert.ok(actualResponse.hasOwnProperty(key), `Missing key: ${key}`); 929 | }); 930 | } 931 | 932 | it('Validating createDispute API', (done)=>{ 933 | webStoreClient.createDispute(createDisputePayload, headers) 934 | .then(validateDisputeAPIResponse) 935 | .then(done) 936 | .catch(done); 937 | }) 938 | 939 | it('Validating getDispute API', (done)=>{ 940 | webStoreClient.getDispute(disputeId,headers) 941 | .then(validateDisputeAPIResponse) 942 | .then(done) 943 | .catch(done); 944 | }) 945 | 946 | it('Validating updateDispute API', (done)=>{ 947 | webStoreClient.updateDispute(disputeId,updateDisputePayload, headers) 948 | .then(validateDisputeAPIResponse) 949 | .then(done) 950 | .catch(done); 951 | }) 952 | 953 | it('Validating contestDispute API', (done)=>{ 954 | webStoreClient.contestDispute(disputeId,contestDisputePayload, headers) 955 | .then(validateDisputeAPIResponse) 956 | .then(done) 957 | .catch(done); 958 | }) 959 | }); 960 | 961 | // ------------ Testing the File APIs --------------- 962 | 963 | describe('WebStore Client Test Cases - File APIs', (done) => { 964 | 965 | const expectedFileAPIResponseKeys =['id', 'type', 'purpose', 'url', 'size', 'uploadTimestamp', 'urlExpirationTimestamp']; 966 | 967 | function validateFileAPIResponse(result) { 968 | assert.strictEqual(result.status, 200); 969 | var actualResponse = result.data; 970 | expectedFileAPIResponseKeys.forEach(key => { 971 | assert.ok(actualResponse.hasOwnProperty(key), `Missing key: ${key}`); 972 | }); 973 | } 974 | 975 | it('Validating FileUpload API', (done)=>{ 976 | webStoreClient.uploadFile(uploadFilePayload, headers) 977 | .then(validateFileAPIResponse) 978 | .then(done) 979 | .catch(done); 980 | }) 981 | }); 982 | }); --------------------------------------------------------------------------------