Every webhook request RemitFlex sends to your endpoint is signed using HMAC-SHA256. Verifying this signature before processing any event ensures that the request genuinely originated from RemitFlex and has not been tampered with in transit. Skipping verification leaves your endpoint vulnerable to spoofed requests from third parties who fabricate event payloads.
How Signing Works
When RemitFlex delivers a webhook, it computes an HMAC-SHA256 digest of the raw request body using your endpoint’s webhook secret as the key. The resulting signature is included in the X-RemitFlex-Signature request header, formatted as:
X-RemitFlex-Signature: sha256=<hmac_hex_digest>
To verify the request, you recompute the same HMAC using the raw body bytes and your secret, then compare your result to the value in the header. If the two match, the request is authentic.
Finding Your Webhook Secret
Each webhook endpoint has its own unique secret. To retrieve it, go to Dashboard → Settings → Webhooks, click on the endpoint you want, then select Reveal Secret. Store this value securely — treat it like a password and never commit it to source control.
Always compute the HMAC over the raw request body bytes, not a re-serialized or parsed version. Parsing the JSON and re-encoding it can change whitespace, key ordering, or encoding — producing a different byte sequence and causing valid signatures to fail verification.
In addition to checking the signature, verify that the created_at timestamp inside the event payload is within 5 minutes of the current time. This prevents replay attacks, where a valid (legitimately signed) request is captured and re-submitted hours or days later.
Responding to Webhooks
Return a 2xx HTTP status code as quickly as possible after verifying the signature. If your endpoint takes too long to respond or returns a non-2xx status, RemitFlex will retry delivery with exponential backoff. To avoid timeouts, acknowledge the request immediately and process the event asynchronously (e.g., push it onto an internal queue).
Verification Examples
The examples below show a complete verification function and a minimal webhook handler for three common server environments.
const crypto = require('crypto');
function verifyRemitFlexWebhook(rawBody, signatureHeader, webhookSecret) {
const expectedSig = crypto
.createHmac('sha256', webhookSecret)
.update(rawBody) // rawBody must be Buffer or string, NOT parsed JSON
.digest('hex');
const expected = `sha256=${expectedSig}`;
// Use timing-safe comparison to prevent timing attacks
if (signatureHeader.length !== expected.length) return false;
return crypto.timingSafeEqual(
Buffer.from(signatureHeader),
Buffer.from(expected)
);
}
// Express.js example — use express.raw() to preserve the original body bytes
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-remitflex-signature'];
if (!verifyRemitFlexWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Guard against replay attacks
const fiveMinutesAgo = Date.now() - 5 * 60 * 1000;
if (new Date(event.created_at).getTime() < fiveMinutesAgo) {
return res.status(400).send('Webhook timestamp too old');
}
// Route event to your handler
switch (event.type) {
case 'offramp.delivered':
// handle off-ramp delivery confirmation...
break;
case 'payment.failed':
// handle payment failure...
break;
}
res.status(200).send('OK');
});