When we make a stripe checkout session we include a success url:
session = await this.stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: lineItems,
payment_intent_data: {
transfer_data: {
amount: 9999999,
destination: someaccountId,
},
},
success_url: `http://localhost:4000/api/checkout/success?true&session_id={CHECKOUT_SESSION_ID}&alias_id=${aliasId}`,
cancel_url: `http://localhost:4000/api/checkout/canceled?session_id={CHECKOUT_SESSION_ID}`,
});
The success URL is where stripe sends the user after a successful payment. It's a GET request since stripe is redirecting the user. Many apps using stripe will need to take actions after a successful checkout- sending an email receipt, notifications, sending paid content, updating the order in the database etc. But it's suggested not to do these actions in GET requests because GET requests are supposed to be idempotent and safe.
For example an unsubscribe link in an email should not unsubscribe a user but instead the "proper approach for unsubscribe links is to lead to a page where the user can click a button to unsubscribe (where the button click triggers a POST request)."src This is because "Many, many, many tools, utilities, web crawlers and other thingamajiggies assume that GET will never be a destructive action (rightly so, since it's specified this way). If you now break your application by breaking that specification, you'll get to keep both parts of your application." src
So I was wondering what is the proper way to handle the stripe success url? If we follow the suggested advice above, then the success url would link to a page where the user clicks a button that updates the order, emails a receipt, etc. But then we are relying on customer to finish the order that has already been paid for. If they don't press that button then important actions aren't completed. What is the proper way to do this? Or does the suggestion to not change the database on a GET request not apply for some reason to these type of actions?
Make the part of that page that handles the Checkout Session code idempotent - i.e. have it check first to see if its steps have already been processed (and in that case skip), or else make it so whatever processing it does could be repeated multiple times without having any additional effect after the first time it runs.
For "tools, utilities, web crawlers and other thingamajiggies" to hit your URL with a valid Checkout Session ID would be pretty close to impossible, so whatever code you use to handle a 'bad session ID' would handle that just fine.
You should also have a webhook for this - which would get a POST request. https://stripe.com/docs/payments/checkout/fulfill-orders#handle-the---event