Webhooks
Receive real-time notifications when payment statuses change.
If you provide a callback_url when creating a payment, we will send a POST request to that URL when the payment status changes.
Payload
POST to your callback_url
{
"payment_id": "vx_a1b2c3d4e5f6a1b2c3d4e5f6_1a2b3c4d",
"amount": "100.00",
"currency": "EUR",
"status": "success",
"links": [
{
"method": "X1",
"status": "success",
"amount": "100.00"
}
],
"updated_at": "2026-03-09T12:05:30.000Z"
}
Signature Verification
Every webhook includes an X-Signature header containing an HMAC-SHA256 signature of the request body. Verify it to ensure the webhook is authentic.
Verification — Node.js
const crypto = require('crypto');
function verify(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Usage in Express:
app.post('/webhook', (req, res) => {
const sig = req.headers['x-signature'];
const raw = req.body; // raw string, not parsed JSON
if (!verify(raw, sig, YOUR_WEBHOOK_SECRET)) {
return res.status(403).send('Invalid signature');
}
// Process webhook...
res.status(200).send('OK');
});
Verification — Python
import hmac, hashlib
def verify(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
Retry Policy
| Condition | Behavior |
|---|---|
Your server returns 2xx | Delivered successfully, no retries |
| Your server returns non-2xx or times out | Retries up to 10 times with exponential backoff (5s, 10s, 20s...) |
Your endpoint should respond within 10 seconds and return
200. Process the webhook asynchronously if needed.