Mantissa Hooksnode is a Mantissa product A Mantissa product mantissatech.xyz
Engineering hooksnode

Payment Webhook Patterns: Routing Transactions Across Multiple Services

Payment webhooks are the most critical events in any fintech or e-commerce system. A single payment event (a successful charge, a refund, a chargeback) needs to reach multiple services: your accounting ledger, your CRM, your analytics pipeline, your notification system, and sometimes your fraud detection service. Here's how to build a reliable payment webhook architecture.

The Problem with Direct Integration

When you integrate a payment processor like Stripe, Flutterwave, or Paystack, the simplest approach is to set up a single webhook endpoint that handles the event inline:

app.post('/webhooks/payments', (req, res) => {
  const event = req.body
  await updateAccountingLedger(event)
  await notifyCustomer(event)
  await updateCRM(event)
  await pushToAnalytics(event)
  res.status(200).end()
})

This works until it doesn't. If the CRM is down, the entire webhook processing pipeline blocks. Notifications don't send, analytics don't update, and the customer gets charged without any of the downstream systems knowing. One failing service takes down your entire payment workflow.

This is where webhook multiplexing changes the game.

Pattern 1: Fan-Out to Multiple Destinations

Instead of chaining all downstream calls sequentially, a webhook multiplexer fans out the event to each destination independently:

  ┌──────────────────┐     ┌──────────────────┐
  │                  │     │  Accounting      │
  │  Payment         │────►│  Ledger          │
  │  Processor       │     ├──────────────────┤
  │  (Stripe/        │     │  CRM             │
  │   Flutterwave)   │────►│  (HubSpot,       │
  │                  │     │   Salesforce)    │
  │  1 webhook       │     ├──────────────────┤
  │  N destinations  │────►│  Analytics       │
  │                  │     │  (Mixpanel,      │
  │                  │     │   PostHog)       │
  │                  │     ├──────────────────┤
  │                  │────►│  Notifications   │
  │                  │     │  (Email, SMS)    │
  └──────────────────┘     └──────────────────┘

Each destination gets its own queue, retry policy, and delivery log. If the CRM is down, the accounting ledger still gets updated. If analytics is slow, notifications still fire. Failures are isolated, not cascading.

Pattern 2: Event-Type Routing with Filters

Not every payment event should go to every service. A chargeback alert is critical for fraud detection but irrelevant to your CRM pipeline. Filter rules let you route events based on payload content:

Destination: Accounting Ledger
Filter: {"event": "charge.succeeded"}
→ Only successful charges hit the ledger

Destination: Fraud Detection
Filter: {"event": "chargeback.created"}
→ Only chargebacks trigger fraud alerts

Destination: Analytics Pipeline
Filter: {"event": ["charge.succeeded",
                    "charge.refunded",
                    "chargeback.created"]}
→ Analytics gets all payment events

This keeps each destination lean. It only receives the events it actually needs to process, reducing noise and processing overhead.

Pattern 3: Idempotent Payment Processing

Payment processors sometimes retry webhook deliveries. Stripe, for example, may retry a webhook if your endpoint does not respond quickly. Without idempotency, a single payment could be processed multiple times.

Hooksnode drops an exact resend of a signed request (the same body and signature) within 10 minutes. Stripe can still deliver the same event more than once, so make each service idempotent on the event id. Paystack uses data.reference. Flutterwave uses data.tx_ref.

Pattern 4: Signature Verification Chain

Payment webhooks carry sensitive data: amounts, customer details, transaction IDs. You need end-to-end authenticity:

  1. Inbound: for Paystack, Flutterwave, Stripe or Meta, pick that provider's signature preset and paste its secret. Hooksnode checks the provider's own header (Stripe uses Stripe-Signature).
  2. Outbound: Sign the forwarded request so each destination can verify it came from your webhook infrastructure

hooksnode checks the inbound signature when the source uses that provider's preset. Presets are in internal/service/sigverify/sigverify.go. When you enable signing on a destination, hooksnode signs every request it forwards with an X-Hooksnode-Signature: sha256=... header. Your downstream services verify this header before processing.

Pattern 5: Payment Reconciliation via Payload Transformation

Different downstream systems need different data shapes. Your accounting system might need flat key-value pairs, while your CRM expects nested objects. Payload transformation lets you reshape the outbound event per destination without changing the original webhook:

// Accounting destination gets flat format
{"transaction_id": "{{.id}}", "amount": {{.amount}}, "currency": "{{.currency}}"}

// CRM destination gets wrapped envelope
{"source": "payment_processor", "event": "charge.succeeded", "data": {{.}}}

// Notification service gets simplified payload
{"customer_email": "{{.billing_details.email}}", "paid_amount": {{.amount}}}

Real-World Example: Multi-Product Payment Routing

A transportation platform like Shuttlers receives payment webhooks from Flutterwave after every ride transaction. The webhook needs to reach:

  • The ride service: to mark the trip as paid and release the driver payment
  • The accounting system: to record revenue per route
  • The customer wallet: to credit loyalty points
  • The analytics pipeline: to track payment success rates per route
  • The notification service: to send the receipt

With direct integration, maintaining this across all products becomes a cross-cutting concern that every team implements differently. With a webhook multiplexer, the payment processor sends to one URL, and hooksnode fans out to each internal service with the right filters, transformations, and retry policies, ensuring every team gets the data they need, reliably.

Key Takeaways

  • Fan-out delivery isolates failures. One downstream service going down doesn't block others
  • Filter rules keep each destination lean by routing only relevant events
  • Make each service idempotent. Hooksnode only drops an exact signed resend for 10 minutes
  • End-to-end signature verification ensures authenticity from processor to destination
  • Payload transformation lets each service receive the data format it needs

hooksnode was built for exactly these patterns. One inbound URL, automatic fan-out, built-in retries with exponential backoff, per-destination filters and transformations, and a live event inspector, so you always know what's happening with your payment webhooks.

Try hooksnode free

No credit card required.

Start free →