ITADN

stripe checkout improvement

#1713Closedsteebchen 创建于 2026-02-22
S
steebchencommented
_⚠️ Potential issue_ | _🔴 Critical_ **Missing idempotency guard — duplicate webhook deliveries will double-credit the organization.** Stripe may deliver `checkout.session.completed` more than once. This handler unconditionally adds credits and inserts a transaction without checking for a prior completed transaction for the same session/payment intent. Compare with the subscription checkout handler (Lines 306-314, 406-414) which checks for an existing transaction by `stripeInvoiceId` before inserting. This handler should apply the same pattern using `stripePaymentIntentId` or the session ID. <details> <summary>Proposed fix — add deduplication check before credit insertion</summary> ```diff const stripePaymentIntentId = session.payment_intent as string | undefined; + // Check for existing transaction to prevent duplicate processing + if (stripePaymentIntentId) { + const existing = await db.query.transaction.findFirst({ + where: { + stripePaymentIntentId: { eq: stripePaymentIntentId }, + type: { eq: "credit_topup" }, + status: { eq: "completed" }, + }, + }); + if (existing) { + logger.info( + `Credit top-up transaction already exists for payment intent ${stripePaymentIntentId}; skipping duplicate`, + ); + return; + } + } + const [completedTransaction] = await db .insert(tables.transaction) ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@apps/api/src/stripe.ts` around lines 560 - 589, Before updating organization credits and inserting the transaction, add an idempotency/deduplication check that queries tables.transaction for an existing completed record matching the Stripe identifier (use stripePaymentIntentId or session.id) and skip the credit update/insert if found; specifically, before the block that updates tables.organization and calls db.insert(tables.transaction) create a lookup (e.g., select where stripePaymentIntentId = stripePaymentIntentId OR metadata/sessionId = session.id) and return early if a completed transaction exists, ensuring the handler (session, stripePaymentIntentId, tables.transaction, db.insert) does not double-credit on repeated webhook deliveries. ``` </details> <!-- fingerprinting:phantom:medusa:phoenix --> <!-- This is an auto-generated comment by CodeRabbit --> _Originally posted by @coderabbitai[bot] in https://github.com/theopenco/llmgateway/pull/1686#discussion_r2820750852_
关闭于 2026-02-22 0 条评论