Webhook Handling
Relevant source files
The following files were used as context for generating this wiki page:
Webhook handling in the SoulSeer platform is primarily designed to facilitate asynchronous communication with Stripe for processing financial transactions. The system ensures that when a user tops up their account balance via a Stripe Payment Intent, the internal database is updated reliably and idempotently to reflect the new balance.
The architecture supports multiple deployment environments, including standalone Express servers and serverless functions (Netlify and Vercel), ensuring consistent signature verification and body parsing across all platforms.
Sources: server/src/index.ts, server/src/routes/webhooks.ts, README.md
Webhook Architecture and Data Flow
The platform provides dedicated endpoints to receive POST requests from Stripe. These endpoints are configured to bypass standard JSON parsing in favor of raw body access, which is required for Stripe's cryptographic signature verification.
Endpoint Mapping
The application maintains several routes for webhook consumption to ensure backward compatibility and compliance with build guides:
POST /api/webhooks/stripe: The canonical endpoint.POST /api/payments/webhook: Supported for backward compatibility.
Sources: server/src/routes/webhooks.ts:1-7, server/src/index.ts:101-103
High-Level Webhook Flow
This diagram illustrates the progression from a Stripe event to the internal database update.
Security and Verification
Security is enforced through signature verification and specialized rate limiting. Every incoming webhook must include a stripe-signature header, which is validated using the stripe.webhooks.constructEvent method and a secret key (config.stripe.webhookSecret).
Technical Implementation Details
- Raw Body Parsing: Unlike standard API routes, webhook routes use
express.raw({ type: "application/json" }). This ensures the signature check is performed against the exact bytes sent by Stripe. - Rate Limiting: A specific
webhookLimiteris applied to these routes to protect against Denial of Service (DoS) attacks while allowing legitimate Stripe traffic. - Idempotency: To prevent duplicate credits (e.g., if Stripe retries a delivery), the system checks the
transactionstable for the existingstripePaymentIntentIdbefore applying updates.
| Security Measure | Description | File Reference |
|---|---|---|
| Signature Validation | Uses Stripe SDK to verify payload authenticity. | server/src/routes/webhooks.ts:31-35 |
| Webhook Limiter | Middleware specifically for webhook routes. | server/src/index.ts:86-88 |
| DB Idempotency | Prevents race conditions and duplicate processing. | server/src/routes/payments.ts:55-70 |
Sources: server/src/index.ts:18, 86-88, server/src/routes/webhooks.ts:24-42
Transaction Logic and Database Integration
When a payment_intent.succeeded event is received, the system performs a multi-step update within a database transaction.
Processing Logic
- Metadata Extraction: The
userIdis retrieved from the Payment Intent'smetadata. If missing, the event is logged as a warning and acknowledged without processing. - Transactional Integrity: A Drizzle ORM transaction ensures that the user's balance update and the creation of the ledger entry (transaction record) succeed or fail together.
- Balance Calculation: The system retrieves the balance before the update to record
balanceBeforeandbalanceAfterin the transaction history for auditing.
Cross-Platform Compatibility
The webhook implementation is designed to work across various runtime environments.
Standalone Server (Fly.io)
In the production Express server, JSON parsing is explicitly skipped for webhook paths to preserve the raw body.
Sources: server/src/production.ts:38-41
Serverless (Netlify & Vercel)
In serverless functions, the same logic is applied. The entry points detect the path and ensure express.json() does not consume the request stream before the webhook handler can access the raw body.
Sources: netlify/functions/api.ts:74-78, api/index.ts:73-77
Conclusion
The SoulSeer Webhook Handling system provides a resilient bridge between Stripe's payment lifecycle and the platform's internal financial ledger. By combining cryptographic verification, strict idempotency checks, and transactional database updates, it ensures client balances are credited accurately and securely across both persistent and serverless deployment models.