Verify Attio Webhook Signatures

Attio signs each webhook with HMAC-SHA256 over the request body using the webhook's secret, and sends the hex digest in the Attio-Signature header. Paste the raw body, the secret from your developer settings and the signature below.

Paste the Attio-Signature value above to compare

Everything runs in your browser — the payload and secret never leave this page. Want to verify a different provider? See the webhook signature verifier hub or the generic HMAC generator.

How Attio signs webhooks

  1. Get the webhook's secret from the Attio developer settings page (also returned by the API when the webhook is created).
  2. Compute HMAC-SHA256 of the raw request body using the secret as the key.
  3. Hex-encode the digest and compare it to Attio-Signature with a constant-time comparison.
  4. Prefer signature verification over IP allowlisting — it keeps working when Attio adds new egress IPs.
References & official docs:

Verify Attio signatures in code

Node.js
const crypto = require('crypto');

function isValidAttioWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected), Buffer.from(signature));
}

const ok = isValidAttioWebhook(
  rawBody,
  req.headers['attio-signature'],
  process.env.ATTIO_WEBHOOK_SECRET);
Python
import hashlib, hmac

def is_valid_attio_webhook(raw_body: bytes, signature: str,
                           secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

Frequently asked questions

Where is the Attio webhook secret?

On the webhook's page in Attio developer settings, and in the API response when the webhook is created. Each webhook has its own secret.

What encoding does the signature use?

Lowercase hex of the HMAC-SHA256 digest — no prefix, no base64. If your computed value looks right but longer or shorter, check you are hex-encoding, not base64-encoding.

Does Attio batch events?

Yes — a single delivery carries an events array, each entry with its own event_type and record identifiers, under one webhook_id. Verify the delivery once, then iterate the array.