Webhooks

Verifying Signatures

Anyone can send a request to a public URL. The signature proves an event really came from Transmit, so check it before you act on anything.

The signature header

X-Transmit-Signature: t=1790431391,v1=5a3f0c…
  • t: When the request was sent, in Unix seconds.
  • v1: An HMAC-SHA256 of {t}.{raw body} signed with your endpoint's secret. Right after you rotate a secret there are two — one per secret.

How to verify

  • 1: Compute an HMAC-SHA256 of t + "." + raw body with your secret, as hex.
  • 2: Accept the event if any v1 value matches it.
  • 3: Reject it if t is more than 5 minutes old — this stops old requests from being replayed.

The example handler does all three in Node.js, Python and PHP.

Common mistakes

  • Using the parsed body: Use the raw bytes. express.json() or bodyParser.json() re-encodes the body and the signature will never match — use express.raw().
  • Checking only the first v1: After a rotation there are two. Check them all.
  • Comparing with ==: Use timingSafeEqual, hmac.compare_digest or hash_equals.
Use the Test button on the Webhooks page to send a signed webhook.test event and check your handler before going live.