Prompt
How do I receive webhook events from Stripe and trigger a workflow?
Latest observation
To receive Stripe webhook events and trigger a workflow, you generally need 3 pieces:
- A publicly reachable webhook endpoint
- Stripe configured to send events to that endpoint
- Server-side code to verify and handle the event, then start your workflow
1) Create a webhook endpoint
Your app needs an HTTP endpoint that accepts POST requests, for example:
https://yourdomain.com/api/stripe/webhook- or a local development tunnel like
https://xxxx.ngrok.app/api/stripe/webhook
Stripe will send event payloads to this URL.
2) Register the endpoint in Stripe
In the Stripe Dashboard:
- Go to Developers → Webhooks
- Click Add endpoint
- Enter your webhook URL
- Select the event types you want, such as:
checkout.session.completedpayment_intent.succeededinvoice.paid
Stripe will give you a signing secret for that endpoint. You’ll use it to verify that events really came from Stripe.
3) Verify the webhook signature
Always verify the signature before trusting the payload.
Stripe sends:
- the request body
- a signature header:
Stripe-Signature
Your server uses the signing secret to validate the event.
Example in Node.js / Express
import express from "express";
import Stripe from "stripe";
const app = express();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
// Stripe webhook requires the raw body, not JSON-parsed body
app.post("/api/stripe/webhook", express.raw({ type: "application/json" }), async (req, res) => {
const sig = req.headers["stripe-signature"];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
sig,
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
console.error("Webhook signature verification failed:", err.message);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle event
try {
switch (event.type) {
case "checkout.session.completed":
// Trigger your workflow here
console.log("Checkout completed:", event.data.object);
break;
case "payment_intent.succeeded":
console.log("Payment succeeded:", event.data.object);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
res.json({ received: true });
} catch (err) {
console.error("Webhook handler failed:", err);
res.status(500).send("Webhook handler failed");
}
});
4) Trigger your workflow
Inside the event handler, call whatever workflow system you use:
- start a background job
- enqueue a message in SQS / RabbitMQ / Redis queue
- call a workflow engine like Temporal, n8n, Zapier, Make, or a custom orchestration service
- update your database and kick off downstream processing
Example: enqueue a job
case "checkout.session.completed":
await queue.add("provision-user", {
sessionId: event.data.object.id,
customerId: event.data.object.customer,
});
break;
5) Return a fast 2xx response
Stripe expects your webhook to respond quickly, usually with a 200 OK.
Don’t do long-running work directly in the request handler if you can avoid it. Instead:
- verify event
- store it / enqueue it
- return 200
- process the workflow asynchronously
This helps prevent retries and timeouts.
Important best practices
- Use the raw request body for signature verification
- Only handle events you care about
- Make handlers idempotent so retries don’t duplicate work
- Log event IDs and store processed IDs if needed
- Use different webhook secrets for test and live environments
- Test with Stripe CLI during development
Testing locally with Stripe CLI
Stripe CLI makes local webhook testing easy:
stripe login
stripe listen --forward-to localhost:3000/api/stripe/webhook
Then trigger a test event:
stripe trigger checkout.session.completed
If you tell me your stack (Node, Python, Next.js, Laravel, etc.) and what workflow engine you want to trigger, I can give you an exact implementation example.