Plaidly Docs

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 OK after successful signature verification.
  • Return a non-2xx status on verification failures.
  • Process only after verifying session_id and status === "completed".

See Webhook concept docs for retry behavior and delivery expectations.

On this page