Booking record created before payment
Why it matters
Creating the booking record inside the payment success webhook — rather than before initiating payment — creates a window where the customer is charged but receives no booking. Stripe webhook delivery can fail, retry with a delay, or be silently dropped by network issues. CWE-362 (race condition) and CWE-841 (behavioral workflow violation) both apply: the system has implicitly split an atomic operation into two steps with no rollback path. The result is a customer whose card was debited, a slot that may or may not be blocked, and a support queue incident that requires manual reconciliation.
Severity rationale
High because webhook delivery failure after a successful charge leaves customers in a provably charged-but-unbookied state, requiring manual intervention for every incident.
Remediation
Create the booking with status='PENDING_PAYMENT' first, pass its ID to the payment provider, then confirm on success. Wire this in your checkout handler (e.g., src/app/api/checkout/route.ts).
// Step 1: persist the booking before touching the payment API
const booking = await db.booking.create({
data: { ...bookingData, status: 'PENDING_PAYMENT' }
});
// Step 2: attach booking ID so the webhook can find the record
const intent = await stripe.paymentIntents.create({
amount,
currency: 'usd',
metadata: { bookingId: booking.id },
});
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Booking Flow & Lifecycle Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-362 — Race Condition / TOCTOU
- cwe · CWE-841 — Improper Enforcement of Behavioral Workflow
- iso-25010:2011 · functional-suitability.functional-correctness
Taxons
History
- 2026-04-18·v1.0.0·Initial import from booking-flow-lifecycle·automated