Payments
Stripe Webhook
Stripe webhook endpoint for processing payment events
POST
Secure webhook endpoint that receives events from Stripe when payment status changes. This endpoint handles payment intent success and failure events, updating the Purchase record status accordingly.
Important Notes
This endpoint is called by Stripe servers, not by your frontend application. Configure this webhook URL in your Stripe Dashboard under Developers → Webhooks.
Webhook Configuration
- In Stripe Dashboard, go to Developers → Webhooks
- Click “Add endpoint”
- Enter URL:
https://api.vaniykempire.com/api/payments/webhook - Select events to listen for:
payment_intent.succeededpayment_intent.payment_failed
- Copy the webhook signing secret to
STRIPE_WEBHOOK_SECRETenvironment variable
Signature Verification
The endpoint verifies webhook authenticity using Stripe’s signature verification:Handled Events
payment_intent.succeeded
Fired when a payment successfully completes. The webhook handler:- Finds the Purchase record by
stripePaymentIntentId - Updates Purchase status to
completed - Logs the successful payment
payment_intent.payment_failed
Fired when a payment fails (card declined, insufficient funds, etc.). The webhook handler:- Finds the Purchase record by
stripePaymentIntentId - Updates Purchase status to
failed - Logs the failed payment
Request Headers
Stripe webhook signature for verifying the request authenticity. Automatically added by Stripe.
Should be
application/jsonRequest Body
The raw Stripe event object. Common fields include:Unique identifier for the event (e.g.,
evt_1MtwBwLkdIwHu7ix28a3tqPa)Event type (e.g.,
payment_intent.succeeded, payment_intent.payment_failed)Event data containing the payment intent object
Response
Always returns
true to acknowledge receipt of the webhookError Handling
If signature verification fails, returns:- Status Code: 400
- Body:
Webhook Error: <error message>
Security Best Practices
- Always verify webhook signatures - Prevents unauthorized requests from spoofing Stripe
- Use raw body parsing - Required for signature verification
- Store webhook secret securely - Use environment variables, never commit to git
- Implement idempotency - Handle duplicate webhook events gracefully
- Return 200 quickly - Stripe will retry if endpoint times out
Webhook Retry Logic
Stripe automatically retries failed webhooks:- If endpoint returns non-2xx status code
- If endpoint times out (after 30 seconds)
- Retries for up to 3 days with exponential backoff
- View retry attempts in Stripe Dashboard
Testing
Local Development
Test Mode
Use Stripe test mode webhook endpoints with test API keys to safely test without affecting production data.Troubleshooting
| Issue | Solution |
|---|---|
| Signature verification fails | Ensure raw body parsing is enabled and webhook secret is correct |
| Purchase not found | Check that payment intent was created through your API |
| Webhooks not received | Verify webhook URL is correct in Stripe Dashboard |
| Duplicate events | Implement idempotency using event ID |
Related Endpoints
- Create Payment Intent - Creates the payment intent that triggers webhooks
- Get Payment Status - Check payment status after webhook processing
Environment Variables
Webhook signing secret from Stripe Dashboard. Format:
whsec_...Implementation Notes
- Middleware:
express.raw({ type: 'application/json' }) - Must be registered before
express.json()middleware - Unhandled event types are logged but don’t cause errors
- Purchase updates are wrapped in try-catch to prevent webhook failures
- Source:
src/controllers/paymentController.js:64-130 - Route configuration:
src/routes/paymentRoutes.js:7-11