Verify Webhook
Validate Plaidly webhook signatures before fulfilling
Verify a Plaidly Webhook
What Plaidly sends
Plaidly sends POST requests with:
X-Plaidly-Event(event type)X-Plaidly-Signature(t=<unix>,v1=<hex>)
Body payload includes:
{
"event_type": "payment_session.completed",
"session_id": "sess_01HX9K...",
"status": "completed",
"amount": 25,
"currency": "USDC",
"chain": "solana",
"network": "mainnet",
"timestamp": 1700000000
}Signature check
import crypto from 'node:crypto';
function isValidPlaidlyWebhook(rawBody, signatureHeader, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(
signatureHeader.split(',').map((part) => part.split('=').map((value) => value.trim())),
);
const ts = Number(parts.t);
const expectedTs = Math.floor(Date.now() / 1000);
if (!ts || Math.abs(expectedTs - ts) > toleranceSeconds) {
return false;
}
const signedPayload = `${parts.t}.${rawBody}`;
const expected = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(parts.v1, 'hex'),
Buffer.from(expected, 'hex'),
);
}rawBody must be the exact request body bytes before JSON parsing.
Acceptance criteria
- Return
200 OKafter successful signature verification. - Return a non-2xx status on verification failures.
- Process only after verifying
session_idandstatus === "completed".
See Webhook concept docs for retry behavior and delivery expectations.