Home > Blockchain >  Successfully process 2 payments or refund to both, using stripe, node, and express
Successfully process 2 payments or refund to both, using stripe, node, and express

Time:02-02

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

  • Related