Prevent same invoice from being processed by webhook handler twice

This commit is contained in:
Artur
2025-04-03 16:31:31 -03:00
parent 138327bc58
commit 0d853f13aa
2 changed files with 48 additions and 3 deletions

View File

@@ -43,7 +43,19 @@ type WebhookBody = Record<string, any> & {
}
async function handleFundingRequiredApiDonation(body: WebhookBody) {
if (!body.metadata) return
if (!body.metadata || JSON.stringify(body.metadata) === '{}') return
const existingDonation = await prisma.donation.findFirst({
where: { btcPayInvoiceId: body.invoiceId },
})
if (existingDonation) {
log(
'warn',
`[BTCPay webhook] Attempted to process already processed invoice ${body.invoiceId}.`
)
return
}
// Handle payment methods like "BTC-LightningNetwork" if added in the future
const cryptoCode = body.paymentMethod.includes('-')
@@ -79,6 +91,18 @@ async function handleFundingRequiredApiDonation(body: WebhookBody) {
async function handleDonationOrMembership(body: WebhookBody) {
if (!body.metadata || JSON.stringify(body.metadata) === '{}') return
const existingDonation = await prisma.donation.findFirst({
where: { btcPayInvoiceId: body.invoiceId },
})
if (existingDonation) {
log(
'warn',
`[BTCPay webhook] Attempted to process already processed invoice ${body.invoiceId}.`
)
return
}
const termToMembershipExpiresAt = {
monthly: dayjs().add(1, 'month').toDate(),
annually: dayjs().add(1, 'year').toDate(),

View File

@@ -10,7 +10,7 @@ import {
stripe as _stripe,
strapiApi,
} from '../../server/services'
import { DonationMetadata, StrapiCreatePointBody } from '../../server/types'
import { DonationMetadata } from '../../server/types'
import { sendDonationConfirmationEmail } from './mailing'
import { getPointsBalance, givePointsToUser } from './perks'
import { NET_DONATION_AMOUNT_WITH_POINTS_RATE, POINTS_PER_USD } from '../../config'
@@ -26,6 +26,18 @@ async function handleDonationOrNonRecurringMembership(paymentIntent: Stripe.Paym
if (JSON.stringify(metadata) === '{}') return
if (metadata.isSubscription === 'true') return
const existingDonation = await prisma.donation.findFirst({
where: { stripePaymentIntentId: paymentIntent.id },
})
if (existingDonation) {
log(
'warn',
`[Stripe webhook] Attempted to process already processed payment intent ${paymentIntent.id}.`
)
return
}
// Skip this event if intent is still not fully paid
if (paymentIntent.amount_received !== paymentIntent.amount) return
@@ -138,12 +150,21 @@ async function handleRecurringMembership(invoice: Stripe.Invoice) {
if (!invoiceLine) {
log(
'info',
'warn',
`[/api/stripe/${metadata.fundSlug}-webhook] Line not fund for invoice ${invoice.id}. Skipping.`
)
return
}
const existingDonation = await prisma.donation.findFirst({
where: { stripeInvoiceId: invoice.id },
})
if (existingDonation) {
log('warn', `[Stripe webhook] Attempted to process already processed invoice ${invoice.id}.`)
return
}
const shouldGivePointsBack = metadata.givePointsBack === 'true'
const grossFiatAmount = invoice.total / 100
const netFiatAmount = shouldGivePointsBack