Stripe - Webhooks
๐ Overviewโ
The Stripe webhooks module manages dynamic webhook registration and configuration for different connected apps (billing, review). Webhooks are automatically registered during app connection and cleaned up on disconnection, enabling real-time event processing for charges, subscriptions, and other Stripe events.
Source Files:
- Controller:
external/Integrations/Stripe/Controllers/auth.js(webhook functions) - Helper:
reviewStripeWebhook()function for review app webhook management
Webhook Endpoints:
- Billing Webhook:
{API_BASE_URL}/v1/billing/webhooks - Review Webhook:
{API_BASE_URL}/v1/reputation/webhook/stripe
๐๏ธ Collections Usedโ
Billing Collectionsโ
- Collections:
billing-charge,billing-dispute,billing-refund,billing-customer,billing-subscription,billing-notes,billing-product - Operations: Create, Update based on webhook events
- Usage Context: Store and update Stripe billing data in real-time
stripe-keyโ
- Operations: Read
- Model:
external/models/stripe-key.js - Usage Context: Track which apps are connected for webhook cleanup logic
๐ Data Flowโ
Webhook Registration Flow (Review App)โ
sequenceDiagram
participant Auth as Auth Controller
participant Stripe as Stripe API
participant DB as Webhook Registry
Auth->>Stripe: List existing webhooks
Stripe-->>Auth: Webhook list
alt Webhook Not Found
Auth->>Stripe: Create webhook endpoint
Stripe->>Stripe: Register URL & events
Stripe-->>Auth: Webhook created (id, secret)
else Webhook Exists
Auth->>Stripe: Update webhook (re-enable)
Stripe-->>Auth: Webhook updated
end
Auth->>DB: Store webhook configuration
Webhook Event Processing Flowโ
sequenceDiagram
participant Stripe as Stripe
participant Webhook as Webhook Endpoint
participant Handler as Event Handler
participant DB as Database
Stripe->>Webhook: POST /v1/billing/webhooks
Note over Webhook: Verify signature
Webhook->>Handler: Process event
alt charge.succeeded
Handler->>DB: Create/Update BillingCharge
else customer.created
Handler->>DB: Create BillingCustomer
else subscription.updated
Handler->>DB: Update BillingSubscription
end
Handler-->>Webhook: 200 OK
Webhook-->>Stripe: Acknowledge receipt
๐ง Business Logic & Functionsโ
reviewStripeWebhook({ stripe, apiBaseUrl })โ
Purpose: Register or update webhook endpoint for automatic review request functionality
Source: Controllers/auth.js
External API Endpoint: POST https://api.stripe.com/v1/webhook_endpoints
Parameters:
stripe(Object) - Initialized Stripe SDK instanceapiBaseUrl(String) - Base URL for webhook endpoint (fromAPI_BASE_URLenv var)
Returns: Promise<WebhookEndpoint>
{
id: "we_...",
object: "webhook_endpoint",
api_version: "2023-10-16",
application: null,
created: 1234567890,
description: "Created by dashclicks...",
enabled_events: ["charge.succeeded"],
livemode: false,
metadata: {},
status: "enabled",
url: "https://api.dashclicks.com/v1/reputation/webhook/stripe"
}
Business Logic Flow:
-
Check Existing Webhooks
for await (const webhook of stripe.webhookEndpoints.list({ limit: 100 })) {
if (webhook?.url == `${apiBaseUrl}/v1/reputation/webhook/stripe`) {
alreadyExist = true;
webhookEndpoint = { ...webhook };
break;
}
}- List all registered webhook endpoints
- Check if review webhook URL already exists
- Store existing webhook if found
-
Create New Webhook (if not exists)
webhookEndpoint = await stripe.webhookEndpoints.create({
url: `${apiBaseUrl}/v1/reputation/webhook/stripe`,
enabled_events: ['charge.succeeded'],
description:
'Created by dashclicks. Deleting might cause failure to send auto review request.',
connect: true,
});- URL: Points to reputation module webhook handler
- Event:
charge.succeeded- Triggered when payment succeeds - Description: Warning about deletion consequences
- Connect:
true- Works with Stripe Connect accounts
-
Update Existing Webhook (if exists)
webhookEndpoint = await stripe.webhookEndpoints.update(webhookEndpoint.id, {
enabled_events: ['charge.succeeded'],
description:
'Created by dashclicks. Deleting might cause failure to send auto review request.',
disabled: false,
});- Re-enables webhook if previously disabled
- Updates event list and description
- Ensures webhook is active
-
Return Webhook Configuration
- Returns webhook endpoint object
- Contains
idfor future reference - Includes
secretfor signature verification
API Request Example:
// Create webhook
POST https://api.stripe.com/v1/webhook_endpoints
Authorization: Bearer {STRIPE_SECRET_KEY}
Content-Type: application/x-www-form-urlencoded
url=https://api.dashclicks.com/v1/reputation/webhook/stripe
enabled_events[]=charge.succeeded
description=Created by dashclicks...
connect=true
API Response Example:
{
id: "we_1234567890abcdef",
object: "webhook_endpoint",
api_version: "2023-10-16",
created: 1697654400,
enabled_events: ["charge.succeeded"],
livemode: false,
status: "enabled",
url: "https://api.dashclicks.com/v1/reputation/webhook/stripe",
secret: "whsec_..." // Used for signature verification
}
Error Handling:
- Network Errors: Logged and re-thrown
- Invalid URL: Stripe returns 400 error
- Duplicate Webhook: Handled by update logic
- Permission Errors: Requires valid Stripe API key
When Called:
- During review app connection in
loginAuth() - During OAuth callback in
postAuth()for review app - On existing connection when adding review app
Side Effects:
- โ ๏ธ Creates webhook endpoint in Stripe account
- โ ๏ธ Updates existing webhook if found
- โ ๏ธ External API call to Stripe (quota counted)
- โ ๏ธ Webhook secret stored in Stripe (not in DashClicks DB)
Billing Webhook Registrationโ
Purpose: Register webhook for billing events (implicit in billing app connection)
Webhook URL: {API_BASE_URL}/v1/billing/webhooks
Enabled Events: All billing-related events
charge.succeededcharge.failedcharge.refundedcustomer.createdcustomer.updatedcustomer.deletedpayment_intent.succeededpayment_intent.failedinvoice.createdinvoice.updatedinvoice.paidinvoice.payment_failedsubscription.createdsubscription.updatedsubscription.deleteddispute.createddispute.updated- And more...
Business Logic:
The billing webhook is registered automatically when the billing app is connected. The registration logic follows a similar pattern to the review webhook but is handled by the billing module itself.
Handler Location: internal/api/v1/billing/webhooks (not in Stripe integration)
Webhook Deletion Logicโ
When Disconnecting Billing App:
// Delete billing webhook
for await (const webhook of stripe.webhookEndpoints.list({ limit: 100 })) {
if (webhook?.url == `${process.env.API_BASE_URL}/v1/billing/webhooks`) {
await stripe.webhookEndpoints.del(webhook.id);
break;
}
}
When Disconnecting Review App:
// Check if other accounts still use review
const isReviewConnected = await StripeModel.findOne({ connected_apps: 'review' });
if (!isReviewConnected) {
// Safe to delete - no other accounts using review webhook
for await (const webhook of stripe.webhookEndpoints.list({ limit: 100 })) {
if (webhook?.url == `${process.env.API_BASE_URL}/v1/reputation/webhook/stripe`) {
await stripe.webhookEndpoints.del(webhook.id);
break;
}
}
}
Deletion Rules:
- Billing Webhook: Deleted immediately when billing app disconnected
- Review Webhook: Only deleted if NO other accounts use review app
- Reason: Review webhook is shared across all accounts using review feature
๐ Integration Pointsโ
Webhook Handlers (External to Stripe Integration)โ
Billing Webhook Handlerโ
- Location:
internal/api/v1/billing/webhooks/stripe.js - Purpose: Process all billing-related Stripe events
- Signature Verification: Uses
stripe.webhooks.constructEvent() - Event Processing:
- Creates/updates records in billing collections
- Syncs Stripe data to local database
- Triggers notifications for payment failures
Review Webhook Handlerโ
- Location:
internal/api/v1/reputation/webhooks/stripe.js - Purpose: Trigger automatic review requests after successful payments
- Signature Verification: Validates webhook authenticity
- Event Processing:
- Listens for
charge.succeededevents - Extracts customer email from charge
- Triggers automated review request email
- Listens for
Internal Servicesโ
- Billing Module: Receives webhook events, updates billing data
- Reputation Module: Receives charge events, sends review requests
- Queue Manager: May process webhook events asynchronously
๐งช Webhook Signature Verificationโ
Security Pattern:
Stripe sends a signature in the Stripe-Signature header to verify webhook authenticity.
Verification Code Example:
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
// In webhook handler
const sig = req.headers['stripe-signature'];
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Process verified event
switch (event.type) {
case 'charge.succeeded':
// Handle charge succeeded
break;
// ... other event types
}
Webhook Secret:
- Retrieved from Stripe webhook endpoint details
- Stored as environment variable:
STRIPE_WEBHOOK_SECRET - Used to verify webhook signatures
๐งช Edge Cases & Special Handlingโ
Shared Review Webhookโ
Issue: Multiple DashClicks accounts may use the review app simultaneously
Handling:
- Review webhook is registered once for the entire platform
- Webhook is NOT deleted when one account disconnects review app
- Only deleted when NO accounts have review app connected
- Prevents breaking review functionality for other accounts
Check Logic:
const isReviewConnected = await StripeModel.findOne({
connected_apps: 'review',
});
if (!isReviewConnected) {
// Safe to delete
}
Webhook Already Existsโ
Issue: Webhook may already be registered (re-connection scenario)
Handling:
- Check existing webhooks before creating
- Update existing webhook instead of creating duplicate
- Ensure webhook is enabled (not disabled)
Billing Webhook Cleanupโ
Issue: Billing data must be deleted when disconnecting
Handling:
- Delete all billing collections data
- Remove webhook endpoint from Stripe
- Ensures no orphaned webhooks or data
Webhook Creation Failureโ
Issue: Webhook registration may fail (network, permissions)
Handling:
- Error logged but does NOT block authentication
- Connection succeeds even if webhook fails
- Manual webhook setup may be required
- User notified of webhook setup failure
โ ๏ธ Important Notesโ
- ๐ Signature Verification: Always verify webhook signatures to prevent spoofing
- ๐ฐ Billing Impact: Webhooks are free but process billable events
- โฑ๏ธ Event Delivery: Stripe retries failed webhook deliveries automatically
- ๐ Idempotency: Webhook handlers should be idempotent (handle duplicate events)
- ๐ Logging: All webhook creation/deletion logged with initiator
- ๐จ Error Handling: Webhook creation failures are logged but non-blocking
- ๐ Shared Webhooks: Review webhook shared across all accounts
- ๐ฏ Event Filtering: Handlers must filter events by
stripe_user_id
๐ Webhook Event Typesโ
Billing Webhook Eventsโ
Payment Events:
charge.succeeded- Payment completed successfullycharge.failed- Payment failedcharge.refunded- Charge refundedcharge.dispute.created- Dispute openedcharge.dispute.closed- Dispute resolved
Customer Events:
customer.created- New customer createdcustomer.updated- Customer details updatedcustomer.deleted- Customer removed
Subscription Events:
customer.subscription.created- New subscriptioncustomer.subscription.updated- Subscription modifiedcustomer.subscription.deleted- Subscription canceledcustomer.subscription.trial_will_end- Trial ending soon
Invoice Events:
invoice.created- New invoice generatedinvoice.updated- Invoice modifiedinvoice.paid- Invoice paidinvoice.payment_failed- Invoice payment failedinvoice.finalized- Invoice finalized
Review Webhook Eventsโ
Enabled Events:
charge.succeeded- Payment completed (triggers review request)
๐ง Testing Webhooksโ
Stripe CLI Testing:
# Install Stripe CLI
stripe login
# Forward webhooks to local development
stripe listen --forward-to localhost:5003/v1/billing/webhooks
# Trigger test events
stripe trigger charge.succeeded
stripe trigger customer.subscription.created
stripe trigger invoice.payment_failed
Manual Testing:
- Create test account in Stripe Dashboard
- Register webhook endpoints in test mode
- Trigger events via Stripe Dashboard
- Monitor webhook delivery in Stripe Dashboard logs
๐ Related Documentationโ
- Integration Overview: Stripe Integration
- Authentication: Authentication Flow
- Stripe Webhook Docs: Stripe Webhooks Documentation
- Event Types: Stripe Event Types
- Signature Verification: Webhook Signatures
๐ฏ Webhook Setup Checklistโ
Before Using:
- Set
API_BASE_URLenvironment variable - Ensure webhook endpoints are publicly accessible
- Set up
STRIPE_WEBHOOK_SECRETfor signature verification - Configure firewall to allow Stripe IPs
When Connecting:
- Verify webhook creation in Stripe Dashboard
- Check webhook status is "enabled"
- Test webhook delivery with test events
- Monitor webhook logs for errors
After Connection:
- Verify events are processed correctly
- Check billing data syncs in real-time
- Monitor review request triggers
- Set up alerting for webhook failures
๐ Webhook Monitoringโ
Key Metrics:
- Webhook delivery success rate
- Event processing latency
- Failed webhook deliveries
- Duplicate event handling
Monitoring Tools:
- Stripe Dashboard webhook logs
- DashClicks application logs
- Database query monitoring
- Error tracking (Sentry, etc.)
Alerting Scenarios:
- Webhook endpoint unreachable
- High failure rate (> 5%)
- Signature verification failures
- Event processing errors