---
title: "Amazon pay V2 integration note with csharp - one-time payments"
description: "記錄使用 C# SDK 串接 Amazon Pay V2 一次性付款的完整流程，從建立 Checkout Session 到 CompleteCheckoutSession 的前後端實作範例。"
canonical_url: "https://blog.markkulab.net/post/amazon-pay-integration"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/author/mark-ku"
site: "Mark Ku's Blog"
date_published: "2023-04-28 01:01:01 +0800"
category: "Payment"
tags: ["amazon-pay", "payment", "csharp", "ecommerce", "integration"]
language: "zh-TW"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "轉載或引用請註明作者並附上原文連結"
---

# Amazon pay V2 integration note with csharp - one-time payments

## Amazon pay integration note with csharp - one-time payments

## Purpose
Our company's Amazon Pay integration often breaks down, so we need to reconnect/reintegrate it

## Prepare
* Amazon pay api key 
* Setting white list of domains in the Amazon pay backend sytem.
* Embedding Amaon pay checkout js in Frontend Web site
* Install Amazon SDK in your backend ( Nuget:Amazon.Pay.API.SDK )

## Doc
* [Get set up for integration](https://developer.amazon.com/docs/amazon-pay-checkout/get-set-up-for-integration.html)
* [Frontend Doc](https://developer.amazon.com/docs/amazon-pay-checkout/v1-amazon-pay-script.html)
* [Backend Doc](https://developer.amazon.com/docs/amazon-pay-api-v2/checkout-session.html)

## Amazon pay demo dite
[Demo Site](https://pay.amazon.com/demo)

### Amazmon pay check out process
* Create Checkout Session - POST 
```
https://pay-api.amazon.com/:version/checkoutSessions
```
* Get Checkout Session - GET 
```
https://pay-api.amazon.com/:version/checkoutSessions/:checkoutSessionId
```
* Update Checkout Session - PATCH 
```
https://pay-api.amazon.com/:version/checkoutSessions/:checkoutSessionId
```
* Complete Checkout Session - POST 
```
https://pay-api.amazon.com/:version/checkoutSessions/:checkoutSessionId/complete
```

## Step1 Embedding Amaon pay checkout js
```
<Script src="https://static-na.payments-amazon.com/checkout.js" strategy="afterInteractive"></Script>
```
## Step2 Call our backend api to Create Amazon Session get signature and payload (backend)

```
private static WebStoreClient InitiateAmazonPayClient() {
         var environment = Projects.InTestingServer ? Environment.Sandbox : Environment.Live;
         var payConfiguration = new ApiConfiguration
         (
             region: Region.UnitedStates,
             environment: environment,
             publicKeyId: AmazonV2.Public_key_id,
             privateKey: AmazonV2.PrivateKey
         );

         var client = new WebStoreClient(payConfiguration);

         return client;
}

public static AmazonCreateCheckoutSession AmazonPayButton(string ChangePaymentReferID) {
         var isChangePayment = !string.IsNullOrEmpty(ChangePaymentReferID);
         var client = InitiateAmazonPayClient();
         var request = new CreateCheckoutSessionRequest(
             checkoutReviewReturnUrl: "http://{your-domain}/carts",
             storeId: Projects.AmazonV2.Store_Id
         );
         request.PaymentDetails.CanHandlePendingAuthorization = false;
         request.DeliverySpecifications.AddressRestrictions.Type = RestrictionType.Allowed;
         request.DeliverySpecifications.AddressRestrictions.AddCountryRestriction("US");
         request.DeliverySpecifications.AddressRestrictions.AddCountryRestriction("CA");

         //generate the button signature
         var signature = client.GenerateButtonSignature(request);
         var payload = request.ToJson();

         return new AmazonCreateCheckoutSession {
            Signature = signature,
            PayloadJSON = payload,
            PublicKeyId = Projects.AmazonV2.Public_key_id,
            MerchantId = Projects.AmazonV2.Merchant_Id,
            IsSandbox = Projects.InTestingServer
         };
      }
```

## Step3 Render Amazon pay button (frontend)

```
async function amazonPaySetting() {
        const resp = await createAmazonCheckoutSession('');
    
        if (reviewItems) {
            updateCartReviewItems(reviewItems);
        }

        if (resp.Success) {
            const data = resp.Data;
            const request = {
                merchantId: data.MerchantId,
                ledgerCurrency: 'USD',
                checkoutLanguage: 'en_US',
                productType: 'PayAndShip',
                placement: 'Cart',
                buttonColor: 'Gold',
                createCheckoutSessionConfig: {
                    payloadJSON: data.PayloadJSON,
                    signature: data.Signature,
                    publicKeyId: data.PublicKeyId,
                },               
                sandbox: process.env.NODE_ENV === 'development' ? true : false,
            };

            
            (window as any).amazon.Pay.renderButton('#AmazonPayButton', request);

            setTimeout(() => {
                if (amazonBtn.current) {
                    amazonBtn.current.click();
                }
            }, 1000);
        }
    }

```
![Amazon Pay快速結帳按鈕](https://blog.markkulab.net/content/markku/posts/amazon-pay-integration/images/E47TLTf.png)

## Step 4 When the user clicks 'Express Checkout', they will be redirected to the payment selection page and can continue with the checkout process (frontend)

![Amazon Pay結帳頁面顯示地址與Visa付款](https://blog.markkulab.net/content/markku/posts/amazon-pay-integration/images/sqc48uc.png)

## Step5 Amazon will redirect to payload's checkoutReviewReturnUrl with checkout session Id (frontend)
![瀏覽器網址列顯示Amazon](https://blog.markkulab.net/content/markku/posts/amazon-pay-integration/images/qhg0FIz.png)

## Step6 Call our backend API to retrieve the checkout session and obtain Amazon shipping information.(backend)
```
public static AmazonV2Result GetPaymentInfo(string AmazonCheckoutSessionId) {
         var client = InitiateAmazonPayClient();
         var getInfo = client.GetCheckoutSession(AmazonCheckoutSessionId);
         var result = new AmazonV2Result {
            Success = false
         };

         if (!getInfo.Success) {
            return GetAmazonIssue(getInfo.RawResponse);
         }

         result.Success = true;
         result.CustomerInfo = FilloutCustomerInfo(getInfo.ShippingAddress, getInfo.Buyer.Email);

         return result;
}
```
![Amazon Pay訂單審核頁面顯示地址](https://blog.markkulab.net/content/markku/posts/amazon-pay-integration/images/eSSlkyq.png)
## Step7 Call our backend API to update the checkout session and retrieve the Amazon purchase URL(backend)
Backend will UpdateCheckoutSession then get Checkout Url with Amazon pay SDK.

```
private static AmazonV2Result UpdateCheckoutSession(string AmazonCheckoutSessionId, AmazonV2Request Data, bool Authorize, string ChangPaymentsReferID) {
         NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

         var result = new AmazonV2Result {
            Success = false,
            AmazonPayRedirectUrl = string.Empty,
            ResponseJson = string.Empty
         };

         try {
            var client = InitiateAmazonPayClient();
            var request = new UpdateCheckoutSessionRequest();
            var isChangPaymentsStep = !string.IsNullOrEmpty(ChangPaymentsReferID);

            request.WebCheckoutDetails.CheckoutResultReturnUrl = isChangPaymentsStep ? ChangePaymentsSuccessLink + ChangPaymentsReferID + "&complete=1" : successLink;
            request.PaymentDetails.ChargeAmount.Amount = Data.OrderAmount;
            request.PaymentDetails.ChargeAmount.CurrencyCode = Currency.USD;
            request.PaymentDetails.CanHandlePendingAuthorization = false;
            request.PaymentDetails.PaymentIntent = Authorize ? PaymentIntent.Authorize : PaymentIntent.AuthorizeWithCapture;
            request.MerchantMetadata.MerchantReferenceId = Data.OrderId;
            request.MerchantMetadata.MerchantStoreName = "ibuypower.com";
            request.MerchantMetadata.NoteToBuyer = Data.ModelName;

            // send the request
            var updateResult = client.UpdateCheckoutSession(AmazonCheckoutSessionId, request);

            // check if API call was successful
            if (updateResult.Success) {
               var josn = DataPackager.Json(updateResult);
            result.Success = true;
               result.AmazonPayRedirectUrl = updateResult.WebCheckoutDetails.AmazonPayRedirectUrl;
               result.ResponseJson = JsonConvert.SerializeObject(updateResult.RawResponse, Formatting.Indented);
            }
            else {
               logger.Error($"[AmazonPay][AmazonV2Helper][PurchaseGetAmazonPayRedirectUrl][UpdateCheckoutSession][Error]Request:{DataPackager.Json(request)},Response:{DataPackager.Json(updateResult)}");
               result.Message = "Please select another credit card or change payment method and try again.";
            }
         }
         catch (Exception ex) {
            logger.Error($"[AmazonPay][AmazonV2Helper][PurchaseGetAmazonPayRedirectUrl][UpdateCheckoutSession][Error]{ex.Message},{ex.StackTrace}");
         }

         return result;
      }

```
## Step8 When a member checks out on Amazon's website, they are redirected to our website with an 'amazonCheckoutSessionId.' This allows us to initiate the 'CompleteCheckoutSession' process.
![Amazon Pay登入成功頁面顯示「Continue as Mark」按鈕](https://blog.markkulab.net/content/markku/posts/amazon-pay-integration/images/BO91nXV.png)  
 ( return to CheckoutResultReturnUrl)

## Step9  CompleteCheckoutSession (backend)

```
private static AmazonV2Result CompleteCheckoutSession(string AmazonCheckoutSessionId, decimal Amount) {
         NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

         AmazonV2Result result = new AmazonV2Result();

         try {
            var client = InitiateAmazonPayClient();
            var request = new CompleteCheckoutSessionRequest(Amount, Currency.USD);
            CheckoutSessionResponse checkoutSessionResponse = client.CompleteCheckoutSession(AmazonCheckoutSessionId, request);

            logger.Info($"[AmazonPay][Success][CompleteCheckoutSession]AmazonCheckoutSessionId:{AmazonCheckoutSessionId},Amount{Amount},Data:{DataPackager.Json(checkoutSessionResponse)}");

            if (checkoutSessionResponse.Success) {
               result.Success = true;
               result.ChargeId = checkoutSessionResponse.ChargeId;
               result.ChargePermissionId = checkoutSessionResponse.ChargePermissionId;
               result.ResponseJson = JsonConvert.SerializeObject(checkoutSessionResponse.RawResponse, Formatting.Indented);
            }
            else {
               result = GetAmazonIssue(checkoutSessionResponse.RawResponse);

               logger.Error($"[AmazonPay][Error][CompleteCheckoutSession][GetAmazonIssue][Step 3]AmazonCheckoutSessionId:{AmazonCheckoutSessionId},Amount{Amount},Data:{DataPackager.Json(checkoutSessionResponse)}");
            }
         }
         catch (System.Exception ex) {
            logger.Error($"[AmazonPay][Error][CompleteCheckoutSession][Step 3]AmazonCheckoutSessionId:{AmazonCheckoutSessionId},Amount{Amount},Ex:{ex.Message},StackTrace:{ex.StackTrace}");
         }

         return result;
      }
```
## Step 10 Finsih 
Amazon pay is a bit complicated, with a lot of page redirections, so it's really difficult to integrate.


## Reference
### (Error Code)[https://developer.amazon.com/docs/amazon-pay-api-v2/charge.html]

---

## 關於本文與作者

本文出自 [Mark Ku's Blog](https://blog.markkulab.net/post/amazon-pay-integration)

授權條款： [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — 轉載或引用請註明作者並附上原文連結

### 關於作者

**[Mark Ku](https://blog.markkulab.net/author/mark-ku)** — Software Solution Provider

- 10+ 年資深軟體工程師，現為 AI 應用 Builder
- 專注大型平台架構設計，從北美電商到AI SaaS訂閱收費系統
- 結合 AI Agent 與自動化，打造高效可演進的產品技術基礎

### 作者開發的免費工具

以下工具皆可免費使用：

- [免費 PDF 簽名工具](https://blog.markkulab.net/tools/pdf-sign): 線上 PDF 簽名工具，瀏覽器內完成手繪、打字、上傳簽名，可拖曳放置、縮放、下載。所有處理都在你的裝置完成，檔案不會上傳。
- [VS Code Refactory](https://blog.markkulab.net/tools/refactory): Refactory 是一款 VS Code 重構擴充套件：34 個重構動作、37 條 code smell 檢查、Code Health 儀表板、18 種語言、534 支測試。懂你的專案慣例：介面放哪、DI 註冊寫在哪、'use client' 該不該加；還會用 git 修改頻率 × 複雜度排出「該先修哪個檔案」，並一鍵把壞味道交給你自己電腦上的 Claude Code 修。免費使用，原始碼不離開你的機器。
- [DB-Kit 資料庫管理工具](https://blog.markkulab.net/tools/db-kit): DB-Kit 是一個用 Tauri + Rust + React 打造的輕量跨平台資料庫管理工具，用單一一致的介面同時管理 MySQL、MariaDB、PostgreSQL、SQL Server、Oracle、SQLite、MongoDB、Redis、Kafka、Elasticsearch 與 RabbitMQ 十一種資料來源：連線密碼以 OS keychain 加密、SSH Tunnel、完整 CRUD、視覺化查詢建構器、多結果集同時顯示、跨連線資料傳輸與比對同步、Excel / CSV 匯入匯出、執行計畫視覺化、ER 圖、排程備份、SQL 壓力測試（p50～p99 延遲百分位）、15 條規則的 SQL 審查、Kafka 訊息瀏覽與監控告警；繁中 / 英文雙語介面，內建 AI 助手（自然語言生成 SQL、AI 審查與調校建議）與命令列工具 dbk。免費開源（MIT），提供 Windows / macOS / Linux 安裝檔。
- [VS Code Super Mermaid](https://blog.markkulab.net/tools/super-mermaid): Super Mermaid 是一款 VS Code 擴充套件：開箱即用的漂亮 Mermaid 圖表，自動上色、即時預覽、滑鼠平移縮放、PNG / SVG 高解析匯出，內建 21 種範本與多種主題。免費開源（MIT）。
- [React Super Mermaid](https://blog.markkulab.net/tools/react-super-mermaid): react-super-mermaid 是一個開源 React 元件庫：一行 <MermaidViewer> 即可渲染漂亮的 Mermaid 圖表，內建 colorful / sketch 主題、平移縮放、圖內搜尋、SVG / PNG 高解析匯出。輕量、SSR 安全、完整 TypeScript 型別。免費開源（MIT）。
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/tools/jira-super-mermaid): Atlassian Forge app：在 Jira issue 與 Confluence 內文直接寫 Mermaid 語法，畫流程圖、時序圖、狀態機與甘特圖。11 種圖表、SVG / PNG 匯出、明暗主題、完整中日韓文字支援。取得 Runs on Atlassian 資格：圖表存在你自己的站台，app 不呼叫任何第三方服務。免費，即將上架 Atlassian Marketplace。
- [Mermaid 線上預覽](https://blog.markkulab.net/tools/mermaid-preview): 在瀏覽器裡寫 Mermaid、即時看圖，整張圖表壓進網址就能分享。免註冊、不上傳伺服器，相容 mermaid.live 的分享連結。
- [React Intl Phone Number](https://blog.markkulab.net/tools/react-intl-phone-number): react-intl-phone-number 是一個開源 React 元件：framework-agnostic、不依賴 antd，提供 E.164 進出、可搜尋國旗 / 國碼下拉、可配置驗證等級（strict / mobile-strict / loose）、可主題化 CSS 與 i18n，電話邏輯由 google-libphonenumber 驅動。輕量、完整 TypeScript 型別。免費開源（MIT）。
- [Uptime Kuma Cluster](https://blog.markkulab.net/tools/uptime-kuma-cluster): 把單機版 Uptime Kuma 改造成高可用叢集：OpenResty + Lua 智慧負載平衡、MariaDB 共享狀態、健康檢查與自動 Failover，附叢集管理 REST API，一行 Docker Compose 啟動。免費開源（MIT）。
- [特教專案](https://blog.markkulab.net/education): 為特殊教育學生製作的學習教材

### 每日 Podcast

- [科技新鮮事](https://blog.markkulab.net/category/tech-news): 每日精選 AI 與科技趨勢，透過語音摘要快速掌握最新技術動態，涵蓋 AI 應用、軟體架構、DevOps 與工程實戰。 — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/category/ai-stock-chat): 每個交易日用 AI 分析台股盤勢，以雙人對話聊當天的盤中觀察與隔日預測。 — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml

### 電子報

[訂閱電子報](https://blog.markkulab.net/subscribe) — 第一時間收到新文章通知，無垃圾信、隨時可取消訂閱。
