Reputation: 768
I'm running a Vue app with a express server. On the client, I'm using the createPaymentIntent, createPaymentMethod, and the confirmCardPayment apis. The documentation clearly states Payment Intents, verifying statuses
Your integration shouldn’t attempt to handle order fulfillment on the client side because it is possible for customers to leave the page after payment is complete but before the fulfillment process initiates. Instead, use webhooks to monitor the payment_intent.succeeded event and handle its completion asynchronously instead of attempting to initiate fulfillment on the client side.
The flow of an order being placed is as follows:
async createOrder() {
this.loading(true);
this.$v.$touch();
if (!this.$v.$invalid) {
// order item details....
const cardElement = elements.getElement("card");
const billingDetails = {
name: user.name,
address: {
city: user.city,
line1: user.street,
state: "NY"
},
phone: user.phone
};
try {
const response = await OrderService.createPaymentIntent(newOrder);
const secret = response.data.clientSecret;
this.deliveryFee = response.data.deliveryFee;
this.totalAmount = response.data.totalAmount;
const paymentMethodRequest = await stripe.createPaymentMethod({
type: "card",
card: cardElement
});
const result = await stripe.confirmCardPayment(secret, {
payment_method: paymentMethodRequest.paymentMethod.id,
shipping: billingDetails,
receipt_email: "[email protected]"
});
// ! DO NOT CONFIRM A SUCCESS ON THE CLIENT, RELY ON THE WEBHOOK!!!!!
// console.log("LINE 443", result, result.error);
if (result.error) {
const error = result.error;
this.showErrorMessage(error);
} else {
this.successfullPayment = true;
this.isLoading = false;
//! NEED TO REDIRECT TO SUCCESSS PAGE
OrderService.postOrder(newOrder).catch(error => {
// https://guillim.github.io/vue/2019/03/20/damn-vuejs-observer.html
this.updateErrors(Object.assign([], error.response.data.errors));
});
console.log("success");
this.updateOrder(newOrder);
}
} catch (error) {
console.log(error);
}
}
My webhook endpoint is pretty much straight from the Stripe docs:
/webhook
static async apiPostWebhookEvent(req, res) {
let data, eventType
let paymentIntent
let event = null
console.log("HITTING STRIPE WEBHOOK")
// Check if webhook signing is configured.
if (process.env.WHSNGROK) { //WHSNGROK hits endpoint
// Retrieve the event by verifying the signature using the raw body and secret.
let signature = req.headers['stripe-signature'];
console.log("SIGNATURE",signature)
try {
event = stripe.webhooks.constructEvent(
req.rawBody,
signature,
process.env.WHSNGROK
);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`);
return res.sendStatus(400);
}
data = event.data;
eventType = event.type;
} else {
// Webhook signing is recommended, but if the secret is not configured in `config.js`,
// we can retrieve the event data directly from the request body.
data = req.body.data;
eventType = req.body.type;
console.log("LINE 38 WEBHOOK", eventType)
console.log("LINE 39", event.type)
}
// event.type || eventType || eventType.type
switch (event.type) {
case 'payment_intent.created':
paymentIntent = event.data.object;
break;
case 'payment_intent.payment_failed':
paymentIntent = event.data.object;
payment_intent.payment_failed
const message = intent.last_payment_error && intent.last_payment_error.message;
console.log('❌ Payment failed.', paymentIntent.id, message);
break;
case 'payment_intent.processing':
paymentIntent = event.data.object;
break;
case 'payment_intent.succeeded':
paymentIntent = event.data.object;
// Then define and call a function to handle the event payment_intent.succeeded
// Funds have been captured
// Fulfill any orders, e-mail receipts, etc
// At this point how do I or can I send the order to MongoDB and get the payment_intent.succeeded confirmation from the webhook to the client?
console.log('💰 Payment captured!', paymentIntent.id);
break;
// ... handle other event types
default:
console.log(`Unhandled event type ${event.type}`);
}
return res.sendStatus(200);
}
}
So to sum up. In the switch/case in the webhook, how can I get the payment_intent.succeeded from the webhook to my client (I understand this is a post request that Stripe is making to my server). That, instead of calling the confirmCardPayment() on the client and relying on that result? Is it possible to call post my newOrder from there or do I still need to call my OrderService.postOrder(newOrder) from the client.
https://stripe.com/docs/api/payment_intents
Upvotes: 1
Views: 1512
Reputation: 494
I think the cleanest way to check whether the webhook has hit your server is to either get the client to ping the server to check the order status every X seconds, or you could establish a web-socket connection between the client and server so that the server can push a message to the client telling it that the paymentIntent
has succeeded (or any other status messages).
Either of those options are fine, although I think it would be safer for the webhook to trigger the update to the Order on the server instead of the client doing that once it receives a response. Otherwise if the connection between the client and the server goes down, then it's possible that the Order will be paid for but not marked as paid and then any other associated actions that the client is meant to carry out will not occur. It's essentially removing any dependency on the client for the Order workflow to be completed once the user has paid for the Order.
Upvotes: 1