Skip to main content

Overview

Merchant webhooks deliver canonical PepayEvent payloads to your backend. They mirror the same event types as merchant WebSockets, but are optimized for durable server-side processing.

Signature verification (SDK)

import express from 'express';
import { createWebhookVerifier } from 'pepay';

const verifier = createWebhookVerifier({
  secrets: [process.env.PEPAY_WEBHOOK_SECRET, process.env.PEPAY_WEBHOOK_SECRET_PREVIOUS].filter(Boolean),
  toleranceMs: 5 * 60 * 1000
});

const app = express();
app.post('/webhooks/pepay', express.raw({ type: 'application/json' }), async (req, res) => {
  const result = await verifier.verify({ rawBody: req.body, headers: req.headers });
  if (!result.valid) return res.status(400).send(result.reason || 'invalid_signature');

  const event = JSON.parse(req.body.toString('utf8'));
  console.log(event.type, event.id);
  return res.status(200).send('ok');
});

Multiple endpoints and rotation

  • If you have multiple endpoints with different secrets, pass a secrets array and verify against any.
  • Use X-Pepay-Network-Environment to route devnet vs mainnet secrets if you want strict separation.
  • During rotation, keep the previous secret configured until all endpoints are updated.

Dedupe and retries

  • Delivery is at-least-once, so dedupe by event.id (or X-Pepay-Event-ID).
  • Expect retries on non-2xx responses.
  • Keep handlers idempotent.

Relationship to WebSockets

  • Merchant WebSockets deliver the same event types as merchant webhooks.
  • The WebSocket stream includes replay + REST backfill for reliable realtime consumption.
  • Webhooks remain best for server-side side effects and audit trails.
Next: WebSockets (merchant)