Skip to content
PingbackDocs
Developer API Beta
DocumentationDeveloper API

Verify signatures

Check authenticity before processing a webhook payload.

Server-side

What Pingback signs

The signature is the hex HMAC-SHA256 of timestamp + '.' + raw_request_body, using your endpoint's signing secret. Preserve the original bytes. Parsing and re-serialising JSON can change the signature.

Verify on your server

No extra dependency · Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

// Pass the untouched HTTP body as a Buffer, before JSON parsing.
export function verifySignature(rawBody, signature, secret) {
  if (!Buffer.isBuffer(rawBody) || !signature || !secret) return false;
  const match = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(signature);
  if (!match) return false;

  const [, timestamp, digest] = match;
  const age = Math.abs(Date.now() / 1000 - Number(timestamp));
  if (age > 300) return false;

  const expected = createHmac("sha256", secret)
    .update(timestamp + ".")
    .update(rawBody)
    .digest();
  const received = Buffer.from(digest, "hex");
  return received.length === expected.length &&
    timingSafeEqual(received, expected);
}

Read X-Pingback-Signature and pass it with the raw body and your saved whsec_ secret. This example rejects timestamps more than five minutes from the server's current time; keep your server clock in sync.

Handle retries safely

After verifying, store X-Pingback-Delivery with the processing result using a unique constraint. An already-processed delivery should return success without applying the same side effect again. Never rely only on an in-memory set.