2

I'm integrating Amazon pay with my website, using the v2 c# SDK from amazon (MVC App), in the sandbox. Setup is all good, I created the keys, return urls, etc.

In my checkout process, I create the CheckoutSession, which is successful. I click on the Amazon Pay button, log in using my test buyer account, and "pay" for the item using their valid test credit card.

Amazon redirects to my return URL with the checkout session id as expected.

When I try to CompleteCheckoutSession, the result is an error back from the Amazon API

error: InvalidCheckoutSessionStatus
message: You tried to call an operation on a Checkout Session that is in a state where that operation is not allowed

I put in a test line of code to retrieve the CheckoutSession to look at it before I try to complete it, and it shows that the current status is "Open", which is the correct status when trying to complete it, so I'm at a loss at why the checkout session status is invalid.

EDIT:

Note I'm using this flow for my transaction, so there is no "review" of the transaction. Buyer chooses his items on my site.

https://amazonpaycheckoutintegrationguide.s3.amazonaws.com/amazon-pay-apb-checkout/additional-payment-button-overview.html

Also note, I'm creating the payload dynamically according to this:

https://amazonpaycheckoutintegrationguide.s3.amazonaws.com/amazon-pay-checkout/amazon-pay-script.html#render-button-using-a-checkout-session-object

So when the amazonpay button is clicked, it calls a method on my site which builds the payload which begins the CheckoutSession. I then have the Amazon Session ID in my cache which I save it, and save the total. The payload is returned to the Amazon pay script which then takes me to the Amazon Site. I choose the payment type and click "continue to checkout", which sends me back to my site with the SessionId to do the "complete" step.

My request to CompleteCheckoutSession(sessionId)

{"chargeAmount":{"amount":99,"currencyCode":"USD"}}

result.RawResponse from the client.CompleteCheckoutSession(sessionId) method:

{
"reasonCode":"InvalidCheckoutSessionStatus",
"message":"You tried to call an operation on a Checkout Session that is in a state where that operation is not allowed"
}

EDIT SAMPLE CODE:

I created a brand new test MVC app with basic functionality:

public ActionResult Index()
{
var client = InitiateClient(); //hidden for security

// prepare the request
var request = new CreateCheckoutSessionRequest
(
    checkoutReviewReturnUrl: "http://localhost:44300/home/completecheckout",
    storeId: "amzn1.application-oa2-client.mystoreid"
);

request.PaymentDetails.PaymentIntent = Amazon.Pay.API.WebStore.Types.PaymentIntent.AuthorizeWithCapture;
request.PaymentDetails.ChargeAmount.Amount = 99;
request.PaymentDetails.ChargeAmount.CurrencyCode = Currency.USD;

// generate the signature and payload string that is passed back to the frontend
ViewBag.Signature = client.GenerateButtonSignature(request);
ViewBag.Payload = request.ToJson();

return View();

}

In the Index.cshtml file:

<div id="AmazonPayButton"></div>
<script src="https://static-na.payments-amazon.com/checkout.js"></script>
<script type="text/javascript" charset="utf-8">
amazon.Pay.renderButton('#AmazonPayButton', {
    merchantId: 'mymerchantid',
    ledgerCurrency: 'USD',
    sandbox: true,

    checkoutLanguage: 'en_US',
    productType: 'PayOnly',
    placement: 'Checkout',
    buttonColor: 'Gold',

    createCheckoutSessionConfig: {
        payloadJSON: '@Html.Raw(ViewBag.Payload)', // string generated in step 2
        signature: '@Html.Raw(ViewBag.Signature)', // signature generated in step 3
        publicKeyId: 'AGPTYXGL5VH6PSYLJUSHTKW6'
    }
});
</script>

And finally, the completecheckout code, which is unsuccessful:

public ActionResult CompleteCheckout(string amazonCheckoutSessionId)
{
    var client = InitiateClient(); //hidden for security
    var request = new CompleteCheckoutSessionRequest(99.00M, Currency.USD);

    // send the request
    var result = client.CompleteCheckoutSession(amazonCheckoutSessionId, request);

    // check if API call was successful
    if (!result.Success)
    {
        throw new Exception("API Call unsuccessful");
    }

    return View();
}

NOTE: certain keys obfuscated, but actual keys are in the sample code.

LarryBud
  • 990
  • 9
  • 20
  • This is after you have been sent back from the Amazon-hosted page (amazonPayRedirectUrl) to your return URL (checkoutResultReturnUrl), right? Did you read the CheckoutSessionID from the URL, or did you cache it somewhere locally? Can you provide the raw response from the API (see the RawResponse property in the AmazonPayResponse object)? – Daniel Lemke Jan 02 '21 at 10:36
  • Hi Dan, yes, this is after I'm sent back from the Amazon hosted page. I read the CheckoutSessionId from the url which matches the session which was created. The error I posted is essentially the RawResponse, which I've added. See my edits. – LarryBud Jan 02 '21 at 12:08

2 Answers2

3

Manually creating the CheckoutSession doesn't work with the "no review page" flow that you are following. If you want to integrate this flow, you'll have to let Amazon Pay create the CheckoutSession for you using the createCheckoutSessionConfig parameter in the button code, see here: https://amazonpaycheckoutintegrationguide.s3.amazonaws.com/amazon-pay-apb-checkout/add-the-amazon-pay-button.html#4-render-the-button

EDIT:

The code sample below shows how to construct the payload and signature for the 'no order review' payment flow. Please note the CheckoutMode parameter, that instructs Amazon Pay to immediately process the payment, and the checkoutResultReturnUrl, that defines the URL where the buyer is sent to for completing the checkout. When the user arrives at that URL, you will have to call Complete CheckoutSession, which should now succeed.

public ActionResult Index()
{
    var client = InitiateClient(); //hidden for security

    // prepare the request
    var request = new CreateCheckoutSessionRequest
    (
        checkoutReviewReturnUrl: null,
        storeId: "amzn1.application-oa2-client.mystoreid"
    );

    // instructs Amazon Pay to immediately process the payment
    request.WebCheckoutDetails.CheckoutMode = CheckoutMode.ProcessOrder;
    request.WebCheckoutDetails.CheckoutResultReturnUrl = "http://localhost:44300/home/completecheckout";

    // payment details
    request.PaymentDetails.PaymentIntent = Amazon.Pay.API.WebStore.Types.PaymentIntent.AuthorizeWithCapture;
    request.PaymentDetails.ChargeAmount.Amount = 99;
    request.PaymentDetails.ChargeAmount.CurrencyCode = Currency.USD;

    // generate the signature and payload string that is passed back to the frontend
    ViewBag.Signature = client.GenerateButtonSignature(request);
    ViewBag.Payload = request.ToJson();

    return View();
}
Daniel Lemke
  • 1,966
  • 18
  • 24
  • Thanks Dan. Is there a way to get the session ID that is created before it redirects me to the Amazon page? – LarryBud Jan 02 '21 at 15:01
  • Also, what is the use case for creating a CheckoutSession manually? – LarryBud Jan 02 '21 at 15:51
  • Not with this integration flow. Manual creating the CheckoutSession is generally not recommended and only still supported for advanced use cases such as asynchronously generating the CheckoutSession in the background to minimize the delay when users click the Amazon Pay button. For the majority of use cases though, the front-end based integration via the createCheckoutSessionConfig is recommended. – Daniel Lemke Jan 02 '21 at 16:59
  • Dan, I changed my flow around and this still didn't work for me. Exactly the same error. My Render Button method is as described in the api ref that you sent me. Clicking the button takes me to Amazon, I select the test CC, the session ID is passed back to me, and when I try to complete the request I get the same message. – LarryBud Jan 02 '21 at 17:56
  • I created some sample code in a paired down MVC app which also fails. – LarryBud Jan 02 '21 at 19:27
  • In your code sample, you have effectively switched to a different flow, as you aren't passing `"checkoutMode": "ProcessOrder"` anymore. This means that the checkout will not assume that you have an 'order review' page, where you present an order summary to the user, rather than immediately completing the payment via the Amazon hosted page. I've added a code sample for the payload generation that shows how the backend code should look like. – Daniel Lemke Jan 03 '21 at 11:28
  • I've tried adding that property, however it throws an error on the Amazon site: When contacting Amazon Pay customer service, provide the following information: Session ID: 131-1474641-5300260 Error Code: InvalidParameterValue – LarryBud Jan 03 '21 at 14:38
  • 1
    Hey Larry, I've tested my code sample in a local project and noticed a small flaw with the SDK as it enforces you to pass the checkoutReviewReturnUrl, which isn't applicable with this integration flow. I've adapted the code sample by setting this parameter to null and passing the missing CheckoutResultReturnUrl parameter, that was probably the root cause for the error that you have seen. Give it a try and let me know if it works. – Daniel Lemke Jan 04 '21 at 08:21
  • I'm afraid that didn't work either. I set the CheckoutResultReturnUrl to the proper URL, set checkoutReviewReturnUrl to null, and now the error is "MissingParameterValue". – LarryBud Jan 04 '21 at 14:01
  • Okay that's odd. Can you copy/paste the complete content of the amazon.Pay.renderButton function as it's rendered in the front-end? There isn't anything secret in there as it's front-end code anyway, but feel free to remove the signature if you want. I'm mostly interested in the payloadJSON parameter's value. – Daniel Lemke Jan 04 '21 at 16:50
  • Dan, I'm going to correct myself. When I created my standalone test app and copy/pasted code, productType: 'PayOnly', was accidentally changed to "PayAndShip" in the cshtml. Once I put it back to PayOnly everything is working as expected with your change to CheckoutResultReturnUrl! Thank you so much for your help! – LarryBud Jan 04 '21 at 16:58
  • 1
    Glad I could help :) – Daniel Lemke Jan 04 '21 at 18:11
  • Hi @DanielLemke, I just want to ask question. I am trying to implement amazon pay button. I did everything just saw here but when logged in to by buyer account it gives me an error "Something went wrong, InvalidRequest (400 Bad Request) I cant pass this error two days. Any ideas ? – Bahadır EKİCİ Jul 29 '22 at 11:13
  • Hey @BahadırEKİCİ, please create a separate question with sample code. The comments section is not the best place for things that aren't directly related to the original thread. – Daniel Lemke Aug 02 '22 at 05:51
3

I had a similar issue and it takes me a very long time to figure it out. This is what happened to me.

I was not intent to create production code. I just want to create a test page with only Amazon Pay button. I used several node js script to getCheckoutSession/updateCheckoutSession. However, when I tried completeCheckoutSession, I got "InvalidCheckoutSessionStatus".

In the end, I found, after I setup all the required parameter and remove all constraint, the updateCheckoutSession gives me a "amazonPayRedirectUrl" in API return. That URL is really important. You need to go that URL in order to complete the review...

This is from Amazon official website:

"Once there are no constraints, the response will return a unique amazonPayRedirectUrl. Redirect the buyer to that URL to complete checkout."

The other way to solve this issue is mentioned by "Daniel Lemke". In that way, shoppers don't need to confirm the session. However, you need to make sure to provide all useful information in webCheckoutDetails (paymentDetails, addressDetails). If you only give checkoutMode, you will get "MissingParameterValue".

This is from Amazon official website:

"paymentDetails is required when using 'ProcessOrder'. addressDetails is also required if you use 'ProcessOrder' with productType set to 'PayAndShip'"

svyat1s
  • 868
  • 9
  • 12
  • 21
chuan qin
  • 31
  • 1
  • This was helpful! In my case I've to provide `checkoutReviewReturnUrl` and `checkoutResultReturnUrl` in order for the API to return a `amazonPayRedirectUrl` that wasn't null. When the users lands in the `checkoutResultReturnUrl` is when the API allows you to call the `completeCheckoutSession` endpoint. – sucotronic Jul 12 '22 at 10:51