2

We have a web page which takes a Stripe payment, once the payment is complete Stripe can call a webhook on our server.

At this point, we can mark an Order as complete and complete any other additional tasks.

How can we have the order webpage update/move the user onto to order complete?

Should we consistently hit the server in AJAX to check if it's now complete, or is there a better way of doing this.

StuartM
  • 6,743
  • 18
  • 84
  • 160
  • I'm not overly familiar with stripe, but the wouldn't the webhook functionality allow you to process the order with a success/fail flag depending on the payments status? – Captain Squirrel Aug 16 '19 at 11:27
  • The question is more in regards to the webpage waiting for the response on that result/update from the webhook. As it would be the main order table, I don't think it's a good idea to regularly poll that for the result as it might cause perf issues, so looking for other suggestions on the overall handling. – StuartM Aug 16 '19 at 11:29
  • You could poll your end point every 30 seconds or so, if you are worried about performance issues? Once the stripe payment hits the webhook, the status of the order is updated which would feed into the customer after your total wait of 30 seconds – Captain Squirrel Aug 16 '19 at 11:31
  • 1
    @StuartM [Use signalR](https://learn.microsoft.com/en-us/aspnet/core/signalr/introduction?view=aspnetcore-2.2). When the request is made, relayed to stripe and return your response. When the webhook is called on server, have signalR pass the response to the client. done. no need to wait or poll – Nkosi Aug 16 '19 at 11:36
  • 1
    What happens at the moment is we get the result from the stripe call and if successful we pass them onto a success page which in turn completes the order in the backend. However, for a very small amount of customers, the order is not complete and stays in a pending payment status. We also have the issue of someone leaving the payment page whilst it is processing and therefore not updating the order to complete. So what we need to do is handle the webhook as a cover. – StuartM Aug 16 '19 at 11:42

3 Answers3

5

Q: How can we have the order webpage update/move the user onto to order complete?

Most payment engines will redirect the payment session to a URL of your choosing with a result code or a different URL per result code. These can generally be configured at the moment the request is being made or for the entire site in a general configuration. These results should not be relied on for the actual payment as that is the job for the web hook. They can be trusted enough for your site to show a general success/fail error message and let the user continue doing whatever.


Stripe also allows for this, you can specify a success_url (or successUrl in the client integration).

See Create a Checkout Session on your server for how to pass this URL to the request. You can also include a cancel_url. See the last 2 parameters in the code sample below:

curl https://api.stripe.com/v1/checkout/sessions \
  -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
  -d payment_method_types[]=card \
  -d line_items[][name]=T-shirt \
  -d line_items[][description]="Comfortable cotton t-shirt" \
  -d line_items[][images][]="https://example.com/t-shirt.png" \
  -d line_items[][amount]=500 \
  -d line_items[][currency]=usd \
  -d line_items[][quantity]=1 \
  -d success_url="https://example.com/success" \
  -d cancel_url="https://example.com/cancel"

See also Checkout Purchase Fulfillment.

When your customer successfully completes their payment or initiates a subscription using Checkout, Stripe redirects them to the URL that you specified in the success_url parameter (or successUrl in the client integration). Typically, this is a page on your website that informs your customer that their payment was successful.

And as I stated above do not rely on this as the actual indicator if the payment succeeded. You should use the web hooks for that.

Do not rely on the redirect to the success_url alone for fulfilling purchases as:

  • Malicious users could directly access the success_url without paying and gain access to your goods or services.
  • Customers may not always reach the success_url after a successful payment. It is possible they close their browser tab before the redirect occurs.
Igor
  • 60,821
  • 10
  • 100
  • 175
  • So we should direct the customer to the order complete/succes_url regardless of if the payment went through yet. Then the webhook handles completing the order – StuartM Aug 19 '19 at 07:54
  • @StuartM - If one of the answers here matches what it is you were asking could you mark it as an answer please? By not marking an answer or awarding the bounty only 1/2 the bounty will be awarded to the top question (the whole bounty amount is still subtracted from your account however). Thanks in advance (see also [bounty](https://stackoverflow.com/help/bounty)). – Igor Aug 23 '19 at 16:01
1

Should we consistently hit the server in AJAX to check if it's now complete, or is there a better way of doing this.

No you shouldn't and yes there is a better way. Callback pages/webhooks would make sense if you didn't have an asp.net server handing the transaction, but they aren't necessary here.

How can we have the order webpage update/move the user onto to order complete?

The stripe payment process only takes a couple seconds to respond with a status code. It's not the same as Paypal where the user is directed to a Paypal site and then back to your site.

The process is supposed to go:

  1. The user enters their payment information into stripe generated elements on your page.

  2. Stripe gives your front end javascript a token that represents the customer's payment data.

  3. You post that information to your server using ajax or even a regular old fashioned form request.

  4. The server side script handling the call uses the asp.net stripe library to send the payment and gets an answer back like the one below.
  5. Save the transaction result to your database as needed.

    a. If the stripe resonse includes "status":"succeeded" then you can serve the customer with a new page with the paid receipt.

    b. If it failed for some reason you can reload the payment page and use the "failure_message" to tell the customer why their card is no good.

Let the user wait until stripe replies with a message regarding the success or failure of the payment and send him because it only takes a second.

    /* SAMPLE RESPONSE FROM STRIPE
    {
    "id": "ch_1D658SDJ46dzUiasdfsdfaDq",
    "object": "charge",
    "amount": 2125,
    "amount_refunded": 0,
    "application": null,
    "application_fee": null,
    "balance_transaction": "txn_1D658SDJ46dzUilftNXRCz64",
    "captured": true,
    "created": 1565431460,
    "currency": "usd",
    "customer": null,
    "description": "856 addresses",
    "destination": null,
    "dispute": null,
    "failure_code": null,
    "failure_message": null,
    "fraud_details": {},
    "invoice": null,
    "livemode": false,
    "metadata": {},
    "on_behalf_of": null,
    "order": null,
    "outcome": {
      "network_status": "approved_by_network",
      "reason": null,
      "risk_level": "normal",
      "seller_message": "Payment complete.",
      "type": "authorized"
    },
    "paid": true,
    "receipt_email": null,
    "receipt_number": null,
    "refunded": false,
    "refunds": {
       "object": "list",
       "data": [],
       "has_more": false,
       "total_count": 0,
       "url": "/v1/charges/ch_1D658SDJ46dzUilfalFFraDq/refunds"
     },
     "review": null,
     "shipping": null,
     "source": {
       "id": "card_1D658RDJ46dzUilfbkLSOIwp",
       "object": "card",
       "address_city": "test",
       "address_country": "US",
       "address_line1": "123 test",
       "address_line1_check": "pass",
       "address_line2": "",
       "address_state": null,
       "address_zip": "32121",
       "address_zip_check": "pass",
       "brand": "Visa",
       "country": "US",
       "customer": null,
       "cvc_check": "pass",
       "dynamic_last4": null,
       "exp_month": 12,
       "exp_year": 2033,
       "fingerprint": "fNMgYIntTkOnLVzk",
       "funding": "credit",
       "last4": "4242",
       "metadata": {},
       "name": "Test",
       "tokenization_method": null
    },
    "source_transfer": null,
    "statement_descriptor": null,
    "status": "succeeded",
    "transfer_group": null
    }
Altimus Prime
  • 2,207
  • 2
  • 27
  • 46
0

Good question, You can handle the stripe payment result to take a new effect on your page

var cardholderName = document.getElementById('cardholder-name');
var cardButton = document.getElementById('card-button');
var clientSecret = cardButton.dataset.secret;

cardButton.addEventListener('click', function(ev) {
  stripe.handleCardPayment(
    clientSecret, cardElement, {
      payment_method_data: {
        billing_details: {name: cardholderName.value}
      }
    }
  ).then(function(result) {
    if (result.error) {
      // Display error.message in your UI.
    } else {
      // The payment has succeeded. update your front-end
    }
  });
});

Should we consistently hit the server in AJAX to check if it's now complete, or is there a better way of doing this.

An Ajax example is here but beter way to doing that is the fetch api. You can find out all detail in here

Hamit YILDIRIM
  • 4,224
  • 1
  • 32
  • 35