Other articles that helped me:
https://www.youtube.com/watch?v=oWK7kesoCQY&t=172s
Other cloud function methods
https://medium.com/@brinorw24/using-stripe-connect-with-flutterflow-1929346c6dc3
This is my code for cloud function payout method:
const functions = require('firebase-functions');const admin = require("firebase-admin");admin.initializeApp();const axios = require('axios');const stripe = require("stripe")(functions.config().stripe.token);exports.stripeWebhook = functions.https.onRequest(async (req, res) => {ย try {ย ย const whSec = functions.config().stripe.payments_webhook_secret;ย ย // Verify the Stripe webhook event signatureย ย const event = stripe.webhooks.constructEvent(ย ย ย req.rawBody,ย ย ย req.headers["stripe-signature"],ย ย ย whSecย ย );ย ย if (event.type === 'checkout.session.completed') {ย ย ย const session = event.data.object;ย ย ย const stripeAccountID = session.client_reference_id;ย ย ย const amountTotal = session.amount_total;ย ย ย const paymentIntent = session.payment_intent;ย ย ย const payeeRef = session.metadata.payeeRef;ย ย ย const payorRef = session.metadata.payorRef;ย ย ย const payeeUsername = session.metadata.payeeUsername;ย ย ย // Construct and send a transfer API callย ย ย try {ย ย ย ย const transferResponse = await axios.post('https://api.stripe.com/v1/transfers', {ย ย ย ย ย amount: amountTotal,ย ย ย ย ย currency: 'usd',ย ย ย ย ย description: 'trush Tips',ย ย ย ย ย destination: stripeAccountID,ย ย ย ย ย // Add other relevant dataย ย ย ย }, {headers: {ย 'Authorization': Bearer ${functions.config().stripe.token},ย 'Content-Type': 'application/x-www-form-urlencoded'}ย ย ย ย });ย ย ย ย console.log(transferResponse.data);ย ย ย ย res.status(200).send('Tips transfer processed successfully');ย ย ย ย ย ย ย ย ย const transferID = transferResponse.data.id;ย ย ย ย // Update Firestore document with success informationย ย ย ย await admin.firestore().collection("tipOrPayout").doc().set({ย ย ย ย ย tipOrPayout: "tips", // Adjust field name to lowercase with underscoresย ย ย ย ย amount: amountTotal,ย ย ย ย ย paymentIntentID: paymentIntent,ย ย ย ย ย transferID: transferID,ย ย ย ย ย payeeUsername: payeeUsername,ย ย ย ย ย payeeRef: payeeRef,ย ย ย ย ย payorRef: payorRef,ย ย ย ย ย status: "Success", // Adjust to "Success" (capitalized first letter)ย ย ย ย ย refund: false,ย ย ย ย });ย ย ย } catch (transferApiError) {ย ย ย ย console.error('Transfer API call failed:', transferApiError);ย ย ย ย res.status(500).send('Error processing webhook, transfer API call failed');ย ย ย ย // Handle the refund API call and Firestore document updateย ย ย ย try {ย ย ย ย ย const refundResponse = await axios.post('https://api.stripe.com/v1/refunds', {ย ย ย ย ย ย payment_intent: paymentIntent,ย ย ย ย ย ย // Add other relevant dataย ย ย ย ย }, {ย headers: {ย ย 'Authorization': Bearer ${functions.config().stripe.token},ย ย 'Content-Type': 'application/x-www-form-urlencoded'ย ย ย ย ย ย }ย ย ย ย ย });ย ย ย ย ย console.log(refundResponse.data);ย ย ย ย ย // Update Firestore document with refund informationย ย ย ย ย await admin.firestore().collection("tipOrPayout").doc().set({ย ย ย ย ย ย tipOrPayout: "tips", // Adjust field name to lowercase with underscoresย ย ย ย ย ย amount: amountTotal,ย ย ย ย ย ย ย paymentIntentID: paymentIntent,ย ย ย ย ย ย transferID: "n/a",ย ย ย ย ย ย payeeUsername: payeeUsername,ย ย ย ย ย ย payeeRef: payeeRef,ย ย ย ย ย ย payorRef: payorRef,ย ย ย ย ย ย status: "Refunded", // Adjust to "Refunded" (capitalized first letter)ย ย ย ย ย ย refund: false,ย ย ย ย ย });ย ย ย ย } catch (refundApiError) {ย ย ย ย ย console.error('Refund API call failed:', refundApiError);ย ย ย ย ย // Handle refund API call errors hereย ย ย ย ย // Update Firestore document with failed refund informationย ย ย ย ย await admin.firestore().collection("tipOrPayout").doc().set({ย ย ย ย ย ย tipOrPayout: "tips", // Adjust field name to lowercase with underscoresย ย ย ย ย ย amount: amountTotal,ย ย ย ย ย ย paymentIntentID: paymentIntent,ย ย ย ย ย ย transferID: "n/a",ย ย ย ย ย ย payeeUsername: payeeUsername, ย ย ย ย ย ย ย payeeRef: payeeRef,ย ย ย ย ย ย payorRef: payorRef,ย ย ย ย ย ย status: "Failed", // Adjust to "Failed" (capitalized first letter)ย ย ย ย ย ย refund: true,ย ย ย ย ย });ย ย ย ย }ย ย ย }ย ย } else {ย ย ย res.status(400).send('Unhandled event type');ย ย }ย } catch (err) {ย ย console.error("Webhook signature verification failed:", err);ย ย res.sendStatus(400);ย }});