Skip to content

feat(billing): send email notification to admin on auto-top-up success#2793

Open
kilo-code-bot[bot] wants to merge 2 commits intomainfrom
feat/auto-topup-success-email
Open

feat(billing): send email notification to admin on auto-top-up success#2793
kilo-code-bot[bot] wants to merge 2 commits intomainfrom
feat/auto-topup-success-email

Conversation

@kilo-code-bot
Copy link
Copy Markdown
Contributor

@kilo-code-bot kilo-code-bot Bot commented Apr 24, 2026

Summary

When an auto-top-up is successfully processed (via the invoice.paid Stripe webhook), an email notification is now sent to the relevant admin:

  • Personal accounts: the user themselves receives the notification
  • Organization accounts: all active org owners receive the notification

The email includes: amount topped up, new balance, which user triggered it, and timestamp. The notification is sent asynchronously via after() to avoid blocking the Stripe webhook response.

Changes:

  • New autoTopUpSuccess.html email template following the existing design system
  • New sendAutoTopUpSuccessEmail() helper in email.ts
  • Notification trigger added to both user and org auto-top-up paths in the invoice.paid webhook handler (stripe.ts)
  • Fixture data added for the admin email testing UI
  • AGENTS.md email template docs updated
  • Fix: processTopupForOrganization() now returns a boolean (true = credits newly applied, false = duplicate/conflict), mirroring the existing processTopUp() pattern. The org notification email is gated on this return value so duplicate invoice.paid webhook retries no longer send spurious emails to org admins.

Verification

  • No manual verification was performed — this is a backend-only change to a Stripe webhook handler. The email template can be previewed and test-sent via the admin email testing UI at /admin/email-testing.

Visual Changes

N/A

Reviewer Notes

  • The email is only sent when processTopUp / processTopupForOrganization returns successfully (not on duplicate/already-registered cases), matching the pattern where autoTopUpOk / orgAutoTopUpOk is true.
  • For the org path, the org's fresh balance is fetched after the credit transaction commits, so new_balance reflects the post-top-up state.
  • Error handling wraps the entire email-sending closure in try/catch with captureException — email failures never affect the billing flow.
  • The IS_IN_AUTOMATED_TEST guard ensures the email sending runs synchronously in tests (same pattern as credits.ts).
  • processedSuccessfully (used for lock management) is still set unconditionally — duplicates should still mark the lock as completed, since the top-up was already processed by a prior webhook.

Built for Lígia Zanchet by Kilo for Slack

Notify org owners (or the user themselves for personal accounts) when
an auto-top-up is successfully processed. The email includes the amount
topped up, new balance, triggering user, and timestamp.

- Add autoTopUpSuccess.html email template
- Add sendAutoTopUpSuccessEmail() helper in email.ts
- Trigger notification in invoice.paid webhook handler (both user and org paths)
- Add fixture data for admin email testing UI
Comment thread apps/web/src/lib/stripe.ts Outdated
const triggeredByUserId =
autoTopUpConfig?.created_by_user_id ?? SYSTEM_AUTO_TOP_UP_USER_ID;

await processTopupForOrganization(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

WARNING: Duplicate invoice.paid retries can send duplicate org success emails

processTopupForOrganization() currently returns void and just returns early on the onConflictDoNothing() path, so this branch cannot tell whether the org top-up was newly applied or already registered. Stripe retries invoice.paid, and those retries will still queue sendOrgNotification(), which means owners can receive another "Auto Top-Up Successful" email even though no new credits were added. Please return an explicit success boolean here and gate the notification the same way the user path does.

@kilo-code-bot
Copy link
Copy Markdown
Contributor Author

kilo-code-bot Bot commented Apr 24, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (6 files)
  • apps/web/src/emails/AGENTS.md
  • apps/web/src/emails/autoTopUpSuccess.html
  • apps/web/src/lib/email.ts
  • apps/web/src/lib/organizations/organization-billing.ts
  • apps/web/src/lib/stripe.ts
  • apps/web/src/routers/admin/email-testing-router.ts

Reviewed by gpt-5.4-20260305 · 426,327 tokens

Make processTopupForOrganization return a boolean (true=credits applied,
false=duplicate) mirroring the existing processTopUp pattern. Gate the
org notification email on that return value so duplicate invoice.paid
webhooks no longer trigger spurious emails to org admins.
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.

0 participants