Webhooks

Configure a webhook in Settings > Webhooks to receive real-time notifications when payment request statuses change.

Events

EventDescription
payment_request.paidPayment request was fully paid
payment_request.pairedA payment was paired to the request (partial or full)
payment_request.canceledPayment request was canceled
payment_request.pendingPayment request was set back to pending

Payload

Each delivery sends a JSON POST request to your webhook URL:

{
  "event": "payment_request.paid",
  "paymentRequestId": "clx1abc...",
  "externalId": "invoice-001",
  "expectedPaymentId": "clx2def...",
  "timestamp": "2026-02-20T12:00:00.000Z"
}

Signature Verification

Every delivery includes an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the raw request body, signed with your webhook secret. Always verify the signature before processing the payload.

import { createHmac } from "crypto";

function verifyWebhookSignature(body, signature, secret) {
  const expected = createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return expected === signature;
}

// In your handler:
app.post("/webhook", (req, res) => {
  const signature = req.headers["x-webhook-signature"];
  const rawBody = req.body; // must be the raw string/buffer

  if (!verifyWebhookSignature(rawBody, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }

  const event = JSON.parse(rawBody);
  console.log("Received:", event.event, event.paymentRequestId);
  res.sendStatus(200);
});

Retry Policy

If your endpoint returns a non-2xx status or times out (10s), the delivery is retried up to 8 times at increasing intervals from the initial attempt:

12345678
Immediate5 min10 min30 min1 h2 h12 h12 h

After 8 failed attempts, the delivery is marked as failed. You can manually retry failed deliveries from the Settings > Webhooks page.