The fix in code
// 1. Server, when the checkout is created
const eventId = `purchase_${checkoutId}`;
await stripe.checkout.sessions.create({
/* line items, urls ... */
metadata: { meta_event_id: eventId },
});
// 2. Browser, on the confirmation page
fbq('track', 'Purchase',
{ value: 299, currency: 'USD' },
{ eventID: eventId });
// 3. Webhook: checkout.session.completed
const id = session.metadata.meta_event_id;
if (await sentStore.has(id)) return; // gateway guard
await capi.send({ event_name: 'Purchase', event_id: id, ... });
Rule source: Meta's deduplication page (event name and ID must match; events are only deduplicated within 48 hours).