Skip to content

Instantly share code, notes, and snippets.

@mmikhan
Created October 1, 2025 09:37
Show Gist options
  • Save mmikhan/9ae8ee511b309a3c1615e4830bb4961c to your computer and use it in GitHub Desktop.
Save mmikhan/9ae8ee511b309a3c1615e4830bb4961c to your computer and use it in GitHub Desktop.
Payload CMS form builder plugin configuration
export default formBuilderPlugin({
fields: {
payment: true,
},
handlePayment: async ({ data, req }) => {
console.log('Payment handler called with hook data:', {
formId: data?.form,
submissionData: data?.submissionData,
payment: data?.payment,
})
const formId = data.form
const submissionData = data.submissionData || []
// Ensure the form ID is valid
if (!formId) {
throw new Error('No form ID provided in submission data')
}
// Get the form document to access price conditions
const formDoc = await req.payload.findByID({
collection: 'forms',
id: formId,
})
// console.log('Form document:', formDoc)
// Define a type for submission data items
type SubmissionDataItem = {
field: string
value: string | number | boolean | null | undefined
// Add other properties if needed
}
// Extract field values from submission data
const fieldValues: Record<string, string | number | boolean | null | undefined> = {}
submissionData.forEach((item: SubmissionDataItem) => {
if (item.field && item.value !== undefined) {
fieldValues[item.field] = item.value
}
})
// Find the payment field to get basePrice and priceConditions
const paymentField = formDoc.fields.find((field: any) => field.blockType === 'payment')
// console.log('Payment field:', paymentField)
if (!paymentField) {
throw new Error('No payment field found in form')
}
// Calculate the total payment amount using the built-in function
const price = getPaymentTotal({
basePrice: paymentField.basePrice || 0,
priceConditions: paymentField.priceConditions || [],
fieldValues,
})
// console.log('Calculated payment amount:', price)
if (price <= 0) {
throw new Error(`Payment amount must be greater than 0. Calculated: ${price}`)
}
try {
// Create a payment intent with Stripe
const paymentIntent = await stripe.paymentIntents.create({
amount: Math.round(price * 100), // Convert to cents
currency: 'usd',
automatic_payment_methods: {
enabled: true,
},
metadata: {
formId: formId?.toString() || 'unknown',
formTitle: formDoc?.title || 'Form Submission',
calculatedAmount: price.toString(),
},
description: `Payment for ${formDoc?.title || 'Form Submission'} - Amount: $${price}`,
})
console.log('Payment intent created successfully:', {
id: paymentIntent.id,
amount: price,
currency: 'usd',
})
// Update the payment data in the submission
data.payment = {
...data.payment,
status: 'succeeded',
amount: price,
paymentProcessor: 'stripe',
transactionId: paymentIntent.id,
}
// Return the payment result
return {
paid: true,
amount: price,
transactionId: paymentIntent.id,
}
} catch (error) {
console.error('Payment processing failed:', error)
// Update payment status to failed
data.payment = {
...data.payment,
status: 'failed',
amount: price,
paymentProcessor: 'stripe',
}
throw new Error(`Payment failed: ${error instanceof Error ? error.message : 'Unknown error'}`)
}
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment