Reliable Stripe & payment webhook processing
Payment events like invoice.paid and charge.failed
cannot be "best effort."
Hooque buffers every webhook instantly, then your workers process with explicit Ack/Nack/Reject control.
The Challenge
Payment webhooks are mission-critical, but they arrive under tight timeouts and get retried aggressively. Never lose Stripe, Paddle, or LemonSqueezy events.
Payment webhooks (invoice.paid, charge.failed, subscription.deleted) are mission-critical — losing one means lost revenue.
Stripe retries aggressively (up to 3 days), creating duplicates when your handler is slow or flaky.
Inline handlers that touch DB + CRM + email in the same request are a single point of failure.
Without a queue, you cannot safely replay failed payment events after incidents.
How Hooque Solves It
Accept Stripe webhooks instantly, then process them at worker speed with explicit delivery controls.
Provider
Stripe
invoice.paid - charge.failed
Buffer
Hooque
Durable queue + delivery controls
Consume
Your service
REST pull or SSE stream
- Respond to Stripe fast (Hooque returns 202 immediately), then process asynchronously.
- Use messageId for idempotency and dedupe across retries.
- Ack, Nack, or Reject each delivery with full lifecycle control.
Before & After
Keep the webhook request lightweight. Pull from your queue and control delivery explicitly.
Without Hooque
Inline DB/CRM calls inside the webhook request
// Express handler does verification and processing inline
import express from "express";
const app = express();
app.use(express.json({ limit: "2mb" }));
// Public webhook endpoint: where should we host it so Stripe can always reach it?
app.post("/stripe/webhook", async (req, res) => {
const signature = req.get("stripe-signature");
// This signature check is often forgotten when teams rush webhook handlers.
if (!verifyStripeSignature(req.rawBody, signature, process.env.STRIPE_WEBHOOK_SECRET)) {
return res.status(400).send("invalid signature");
}
try {
// Hope we do not timeout while processing inline.
await process_payment_payload(req.body); // invoice.paid, charge.failed, ...
res.sendStatus(200);
} catch (err) {
// Do we need to send an alert here?
// How do we know which payload failed and how to debug it later?
res.sendStatus(500);
}
}); With Hooque
Workers pull, process, and Ack/Nack using action URLs
// Stream Stripe events from Hooque over SSE
const HOOQUE_URL = process.env.HOOQUE_URL; // e.g. https://app.hooque.io/queues/cons_stripe_payments
const TOKEN = process.env.HOOQUE_TOKEN;
const headers = { Authorization: `Bearer ${TOKEN}` };
// Signature verification is handled by Hooque before messages enter this stream.
const streamResp = await fetch(HOOQUE_URL + "/stream", { headers });
for await (const line of readSseLines(streamResp.body)) {
if (!line.startsWith("data:")) continue;
const event = JSON.parse(line.slice(5)); // { payload, meta }
const payload = event.payload;
const meta = event.meta;
try {
await process_payment_payload(payload); // invoice.paid, charge.failed, ...
await fetch(meta.ackUrl, { method: "POST", headers });
} catch (err) {
// Failed message can be inspected in Hooque, and we receive an alert about it.
await fetch(meta.nackUrl, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ reason: String(err) }),
});
}
} Key Benefits
Make payment processing predictable: no missing events, no panic replays.
Reliable payment processing
Persist every webhook instantly so revenue-critical events cannot vanish during outages.
Idempotency via message IDs
Use messageId as a stable dedupe key across retries and re-deliveries.
Throughput visibility
Track how many payment events are queued, in-flight, delivered, and rejected in real time.
How It Works
Set up once, then let your workers process payments reliably in the background.
Create a webhook
Create a Hooque webhook in your dashboard and copy the hosted endpoint URL.
Point Stripe to Hooque
Set the webhook URL in Stripe. Hooque accepts the event and returns instantly.
Consume from the queue
Pull via REST or stream via SSE, then Ack/Nack/Reject each delivery.
Related guides
Deeper dives on the production mechanics behind this use case.
Webhook API
Delivery lifecycle, timeouts, and safe processing patterns.
Read the guide
Webhook security
Signatures, replay protection, and secret rotation.
Read the guide
Retries and backoff
Idempotency and duplicate-proof retry handling.
Read the guide
Migrate to queue-based processing
Step-by-step plan to move off inline handlers.
Read the guide
Payment webhooks FAQ
Answers to common questions about retries, idempotency, and signature verification across providers.
Still have questions?
Contact our support teamStart Processing Stripe Webhooks in 2 Minutes
Get a hosted endpoint and a durable queue. Keep your billing pipeline reliable even when your systems are not.
Start for freeNo credit card required