Use Case

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.

1

Create a webhook

Create a Hooque webhook in your dashboard and copy the hosted endpoint URL.

2

Point Stripe to Hooque

Set the webhook URL in Stripe. Hooque accepts the event and returns instantly.

3

Consume from the queue

Pull via REST or stream via SSE, then Ack/Nack/Reject each delivery.

FAQ

Payment webhooks FAQ

Answers to common questions about retries, idempotency, and signature verification across providers.

Yes. Most payment providers expect a fast 2xx and will retry on timeouts or non-2xx. With Hooque, the hosted endpoint verifies and persists the event first, then acknowledges quickly so your worker can process asynchronously.
Assume retries and duplicates. Use the provider event id (or the message id you consume) as an idempotency key, and make your side effects safe to run more than once.
Enable provider verification (for example Stripe, Paddle, or LemonSqueezy) so invalid signatures are rejected at ingest before anything enters your queue. If you are using an unsupported provider, you can still secure ingest with token protection or generic HMAC.
Providers still deliver to Hooque, and events stay queued until your worker comes back. Your consumer acks when it's done, or nacks/rejects with a reason.
Yes. You can inspect queued/delivered/rejected messages, then reprocess safely using the same idempotency key strategy.
Both. Use SSE for real-time processing, or REST pull for batch jobs and cron-style workers.

Still have questions?

Contact our support team

Start 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 free

No credit card required