Skip to content

Conversation

@AdityaK2905
Copy link
Contributor

@AdityaK2905 AdityaK2905 commented Oct 27, 2025

Summary by CodeRabbit

  • New Features
    • Automatic recording and acknowledgement of successful Stripe payments (captures amount, currency, status, billing email, timestamp, and event identifier).
  • Chores
    • Added a configuration option to specify where Stripe payment records are stored.
  • Continued
    • Continued support for bank transfer funding and automatic tracking of bank-transfer transactions.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 27, 2025

💰 Infracost report

Monthly estimate generated

This comment will be updated when code changes.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 27, 2025

Walkthrough

Adds handling for Stripe payment_intent.succeeded webhook: verifies signature, parses event, extracts amount, currency, billing email, domain, and eventId; writes a record to the configured DynamoDB table via PutItemCommand (pk "<acm_org>#<domain>", sk event.id); logs and returns a handled response. Adds StripePaymentsDynamoTableName to config.

Changes

Cohort / File(s) Summary
Stripe webhook handler
src/api/routes/stripe.ts
Imported PutItemCommand; added payment_intent.succeeded case that verifies signature, parses event payload, extracts amount, currency, billingEmail, eventId, resolves domain, and issues a PutItemCommand to StripePaymentsDynamoTableName with primaryKey "<acm_org>#<domain>", sortKey event.id, and item fields amount, currency, status, billingEmail, createdAt, eventId; logs success and returns { handled: true, requestId }; errors logged and converted to DatabaseInsertError on failure.
Configuration
src/common/config.ts
Added StripePaymentsDynamoTableName: string to GenericConfigType and initialized genericConfig.StripePaymentsDynamoTableName = "infra-core-api-stripe-payments".

Sequence Diagram(s)

sequenceDiagram
    participant Stripe as Stripe Service
    participant Handler as Webhook Handler
    participant DDB as DynamoDB
    participant Client as HTTP Client

    Stripe->>Handler: POST webhook (payment_intent.succeeded + signature)
    activate Handler
    Handler->>Handler: Verify signature & parse event
    alt event == payment_intent.succeeded
        Handler->>Handler: Extract amount, currency, billingEmail, domain, eventId
        Handler->>DDB: PutItemCommand -> StripePaymentsDynamoTableName\n(pk: "<acm_org>#<domain>", sk: event.id)
        activate DDB
        DDB-->>Handler: PutItem result
        deactivate DDB
        Handler->>Client: 200 { handled: true, requestId }
    else
        Handler->>Client: 200 / ignored
    end
    deactivate Handler
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Check webhook signature verification, parsing, and error mapping in src/api/routes/stripe.ts.
  • Validate DynamoDB key construction "<acm_org>#<domain>", event.id usage, attribute types/marshalling, and idempotency.
  • Confirm createdAt format and timezone consistency.
  • Ensure StripePaymentsDynamoTableName is used correctly and documented in config.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'Stripe webhook updates for ACH transfer' is vague and does not accurately describe the main changes, which involve handling payment_intent.succeeded events and storing Stripe payments in DynamoDB. Update the title to be more specific about the actual implementation, such as 'Handle payment_intent.succeeded webhook and store payments to DynamoDB' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch stripeWebhookChanges

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a68b9a8 and 2ee6c0b.

📒 Files selected for processing (2)
  • src/api/routes/stripe.ts (3 hunks)
  • src/common/config.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Unit Tests
  • GitHub Check: Build Application
🔇 Additional comments (3)
src/common/config.ts (1)

43-43: LGTM! Configuration addition is consistent.

The new StripePaymentsDynamoTableName field follows existing naming conventions and patterns in the codebase.

Also applies to: 87-87

src/api/routes/stripe.ts (2)

6-6: LGTM! Import correctly added.

The PutItemCommand import is properly placed with other DynamoDB commands and is necessary for the new webhook handler.


767-770: LGTM! Return handling is correct.

The case properly returns a success response and is structured consistently with other webhook handlers in this file.

@gitguardian
Copy link

gitguardian bot commented Oct 28, 2025

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/api/routes/stripe.ts (2)

734-748: Add error handling around DynamoDB operation.

This issue was previously flagged: The PutItemCommand lacks error handling. If the database write fails, the webhook will throw an unhandled error, and Stripe will retry the webhook repeatedly.

Wrap the DynamoDB operation in a try-catch block consistent with other DynamoDB operations in this file (lines 85-94, 171-186):

+          try {
             await fastify.dynamoClient.send(
               new PutItemCommand({
                 TableName: genericConfig.StripePaymentsDynamoTableName,
                 Item: marshall({
                   primaryKey: `${acmOrg}#${domain}`,
                   sortKey: `customer`,
                   amount,
                   currency,
                   status: "succeeded",
                   billingEmail: email,
                   createdAt: Date.now(),
                   eventId: event.id,
                 }),
               }),
             );
+          } catch (e) {
+            if (e instanceof BaseError) {
+              throw e;
+            }
+            request.log.error(e);
+            throw new DatabaseInsertError({
+              message: "Could not write payment transaction to database.",
+            });
+          }

744-744: Use ISO string format for createdAt to maintain consistency.

This issue was previously flagged: Line 744 uses Date.now() which returns a numeric timestamp, but elsewhere in this file (e.g., line 162), createdAt is stored as an ISO string via new Date().toISOString(). This inconsistency could cause issues when querying or displaying dates.

Apply this diff:

                 status: "succeeded",
                 billingEmail: email,
-                createdAt: Date.now(),
+                createdAt: new Date().toISOString(),
                 eventId: event.id,
               }),
🧹 Nitpick comments (1)
src/api/routes/stripe.ts (1)

732-732: Add validation for email domain extraction.

The domain extraction using email.split("@")[1] could fail if the email format is unexpected (e.g., missing '@' symbol, multiple '@' symbols). While the email has fallbacks, it's safer to validate the extraction.

Consider adding validation:

           const email =
             intent.receipt_email ??
             intent.metadata?.billing_email ??
             "unknown@example.com";
           const acmOrg = intent.metadata?.acm_org ?? "ACM@UIUC";
-          const domain = email.split("@")[1] ?? "unknown.com";
+          const emailParts = email.split("@");
+          const domain = emailParts.length === 2 ? emailParts[1] : "unknown.com";
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 2ee6c0b and 24767dd.

📒 Files selected for processing (1)
  • src/api/routes/stripe.ts (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Unit Tests
  • GitHub Check: Build Application

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/api/routes/stripe.ts (3)

732-746: Add error handling around DynamoDB operation.

The PutItemCommand lacks error handling, unlike similar DynamoDB operations elsewhere in this file (lines 85-94, 171-186). If the database write fails, the webhook will throw an unhandled error.

Apply this diff to add error handling consistent with other DynamoDB operations:

+          try {
             await fastify.dynamoClient.send(
               new PutItemCommand({
                 TableName: genericConfig.StripePaymentsDynamoTableName,
                 Item: marshall({
                   primaryKey: `${acmOrg}#${domain}`,
                   sortKey: `customer`,
                   amount,
                   currency,
                   status: "succeeded",
                   billingEmail: email,
                   createdAt: Date.now(),
                   eventId: event.id,
                 }),
               }),
             );
+          } catch (e) {
+            if (e instanceof BaseError) {
+              throw e;
+            }
+            request.log.error(e);
+            throw new DatabaseInsertError({
+              message: "Could not write payment transaction to database.",
+            });
+          }

736-737: Data model will overwrite previous payments.

The current DynamoDB key structure (primaryKey: "${acmOrg}#${domain}" and sortKey: "customer") means only one payment record can exist per organization-domain combination. Each subsequent payment from the same domain will overwrite the previous record, causing data loss.

Consider using the payment intent ID as the sort key to ensure uniqueness:

             Item: marshall({
               primaryKey: `${acmOrg}#${domain}`,
-              sortKey: `customer`,
+              sortKey: `PAYMENT#${intent.id}`,
               amount,
               currency,
               status: "succeeded",
               billingEmail: email,
+              customerId,
               createdAt: Date.now(),
               eventId: event.id,
             }),

742-742: Use ISO string format for createdAt to maintain consistency.

Line 742 uses Date.now() which returns a numeric timestamp, but elsewhere in this file (line 162), createdAt is stored as an ISO string via new Date().toISOString(). This inconsistency could cause issues when querying or displaying dates.

Apply this diff:

               status: "succeeded",
               billingEmail: email,
-              createdAt: Date.now(),
+              createdAt: new Date().toISOString(),
               eventId: event.id,
             }),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 24767dd and babe292.

📒 Files selected for processing (1)
  • src/api/routes/stripe.ts (2 hunks)
🧰 Additional context used
🪛 GitHub Actions: Required Reviews
src/api/routes/stripe.ts

[error] Requirement "Base Requirement" is not satisfied. No reviews from required reviewers (Members of officers, infra-chairs, or infra-leads).

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Unit Tests
  • GitHub Check: Build Application
🔇 Additional comments (1)
src/api/routes/stripe.ts (1)

748-754: LGTM: Logging and response handling.

The logging statement provides useful information for tracking payments, and the response format is consistent with other webhook handlers in this file.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9fcaf0b and 54d91eb.

📒 Files selected for processing (1)
  • src/api/routes/stripe.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Unit Tests
  • GitHub Check: Build Application

@AdityaK2905 AdityaK2905 changed the title implemented webhook handling for customer_cash_balance_transaction.cr… Stripe webhook updates for ACH transfer Nov 3, 2025
@devksingh4 devksingh4 merged commit 922d017 into main Nov 4, 2025
13 of 15 checks passed
@devksingh4 devksingh4 deleted the stripeWebhookChanges branch November 4, 2025 03:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modify Stripe webhook handler to correctly handle webhook requests for bank transfers

3 participants