I will be using node express and stripe to process payments of my users. There is an edge case where it must process payment for 2 users sequentially. And if the second payment fails to process, then the first payment must be refunded.
The user's payment info / options are stored.
How can this be implemented?
CodePudding user response:
You can do that using stripe webhooks and a database.
You can call all interactions orders
. For example this would be an instance of the order
interface Order {
id: string;
user1: string;
user2: string;
user1Succeeded: boolean;
user2Succeeded: boolean;
paymentIntent1: string;
paymentIntent2: string;
}
And store the orders in some database.
Create an order
User1 makes a POST request to /create-order
endpoint:
router.post("/create-order", async (req, res) => {
const orderId = "ORDERID"
// create a payment intent and send it to User1
const paymentIntent = await stripe.paymentIntents.create({
amount: 123,
currency: "USD",
metadata: {
orderId: orderId, // save order id so then when payment
// succeeded you know what order to handle
userId: "USER1"
}
});
// create an order and store it in database
// so other users can join the order
await createOrder({
id: orderId,
user1: "USER1",
paymentIntent1: paymentIntent.id
});
res.send({ clientSecret: paymentIntent.client_secret });
})
Then a different user wants to join the order and makes a POST request to /join-order
endpoint:
router.post("/join-order/:orderId", async (req, res) => {
const { orderId } = req.params;
// create a payment intent and send it to User2
const paymentIntent = await stripe.paymentIntents.create({
amount: 123,
currency: "USD",
metadata: {
orderId: orderId, // save orderId so when payment succeeds you
// know what order to change
userId: "USER2"
}
});
// JOIN an order and update it in database
await updateOrder(orderId, {
user2: "USER2",
paymentIntent2: paymentIntent.id
});
res.send({ clientSecret: paymentIntent.client_secret });
})
Handle payment intents
Use stripe webhooks to handle when payment intends succeeds:
router.post("/stripe-webhook", async (req, res) => {
if(event.type == "payment_intent.succeeded") {
const data = event.data.object as Stripe.PaymentIntent;
const orderId = data.metadata.orderId; // the order id that was saved earlier
const userId = data.metadata.userId; // the user id that was saved earlier
const order = await getOrder(orderId);
// update the order so you know later that other user succeeded
if(order.user1 == userId) {
await updateOrder(orderId, { user1Succeeded: true });
if(order.user2Succeeded) { // both users succeeded
// ORDER COMPLETED, NO REFUNDS
}
} else if(order.user2 == userId) {
await updateOrder(orderId, { user2Succeeded: true });
if(order.user1Succeeded) { // both users succeeded
// ORDER COMPLETED, NO REFUNDS
}
}
}
if(event.type == "charge.failed") { // one of the payments failed
// cancel or refund other
const data = event.data.object as Stripe.Charge;
const { orderId } = data.metadata;
const order = await getOrder(orderId);
if(order.user1Succeeded) {
// REFUND USER1
stripe.refunds.create({ payment_intent: order.paymentIntent1 });
} else {
// if user1 didn't pay yet cancel the payment intent
stripe.paymentIntents.cancel(order.paymentIntent1);
}
if(order.user1Succeeded) {
// REFUND USER2
stripe.refunds.create({ payment_intent: order.paymentIntent1 });
} else {
// if user2 didn't pay cancel his payment intent
stripe.paymentIntents.cancel(order.paymentIntent2);
}
}
});
I'm guessing what you need is Stripe webhooks. Here is how to monitor Payment Intent status