When an event is cancelled, automatically refund all ticket purchases:
src/actions/refund-event-ticket.ts
import { stripe } from '@/lib/stripe';import { getConvexClient } from '@/lib/convex';import { api } from '../../convex/_generated/api';export async function refundEventTickets(eventId: Id<"events">) { const convex = getConvexClient(); const event = await convex.query(api.events.getById, { eventId }); if (!event) throw new Error("Event not found"); // Get event owner's Stripe Connect ID const stripeConnectId = await convex.query( api.users.getUsersStripeConnectId, { userId: event.userId } ); if (!stripeConnectId) { throw new Error("Stripe Connect ID not found"); } // Get all valid tickets for this event const tickets = await convex.query(api.tickets.getValidTicketsForEvent, { eventId, }); // Process refunds for each ticket const results = await Promise.allSettled( tickets.map(async (ticket) => { if (!ticket.paymentIntentId) { throw new Error("Payment information not found"); } // Issue refund through Stripe await stripe.refunds.create( { payment_intent: ticket.paymentIntentId, reason: "requested_by_customer", }, { stripeAccount: stripeConnectId, } ); // Update ticket status to refunded await convex.mutation(api.tickets.updateTicketStatus, { ticketId: ticket._id, status: "refunded", }); return { success: true, ticketId: ticket._id }; }) ); // Check if all refunds were successful const allSuccessful = results.every( (result) => result.status === "fulfilled" && result.value.success ); if (!allSuccessful) { throw new Error( "Some refunds failed. Please check the logs and try again." ); } // Cancel the event await convex.mutation(api.events.cancelEvent, { eventId }); return { success: true };}
Refunds are processed through the event organizer’s connected Stripe account. Ensure they have sufficient balance or Stripe will automatically debit from their bank account.