Configure a webhook in Settings > Webhooks to receive real-time notifications when payment request statuses change.
| Event | Description |
|---|---|
payment_request.paid | Payment request was fully paid |
payment_request.paired | A payment was paired to the request (partial or full) |
payment_request.canceled | Payment request was canceled |
payment_request.pending | Payment request was set back to pending |
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"
}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);
});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:
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|
| Immediate | 5 min | 10 min | 30 min | 1 h | 2 h | 12 h | 12 h |
After 8 failed attempts, the delivery is marked as failed. You can manually retry failed deliveries from the Settings > Webhooks page.