Skip to main content
Every webhook Fit Pro Tracker delivers carries a cryptographic signature in the X-FPT-Signature header. Verifying this signature on every request proves the payload genuinely came from us and hasn’t been tampered with in transit.
Verify the signature on every request, before any processing. Don’t trust the body, don’t read the eventType, don’t even log the payload until verification passes. An unsigned or invalid request should return 401 Unauthorized immediately.

The signature header

Two fields, comma-separated:

The signing scheme

Where:
  • {t} is the same timestamp value from the header
  • {rawBody} is the exact request body, byte-for-byte — don’t re-serialize the JSON (whitespace changes break the signature)
  • secret is the 32+ character secret revealed once when you click Generate Key on your subscription

Verification recipe (language-agnostic)

1

Parse the X-FPT-Signature header

Split on ,. Pull out t and v1. Reject if either is missing.
2

Reject ancient timestamps

Check now - t > 300 (5 minutes). Reject as 401 — defends against replay attacks if a signature ever leaks.
3

Read the raw body, exactly as received

Don’t parse, don’t pretty-print, don’t strip whitespace. Capture the bytes.
4

Compute the expected signature

expected = HMAC_SHA256(secret, "{t}.{rawBody}"). Hex-encode it.
5

Constant-time compare

Use a constant-time comparison function (hmac.compare_digest in Python, crypto.timingSafeEqual in Node, CryptographicOperations.FixedTimeEquals in .NET). Never use == on the strings — it leaks the secret via timing side channels.
6

Reject mismatches with 401

Don’t expose details about why it failed — that helps attackers.

Code samples

Key rotation

Click Rotate Key on your subscription’s row in Settings → Webhook Endpoints to issue a new secret. The dialog reveals the new secret once — save it.
No grace period — the old secret is invalidated immediately on rotation. There is no overlap window where both work. Plan the order carefully:
  1. Rotate the secret in the FPT admin and save the new value
  2. Deploy the new secret to your endpoint config (or your secrets manager)
  3. Use Send Test Event to verify your endpoint accepts the new signature before relying on real traffic
  4. Done
If you accidentally compromise a key (lose it, leak it, push it to a public repo), rotate immediately. Events delivered between the leak and the rotation should be considered untrusted.

Common verification mistakes

Your framework probably parses the body into a req.body object before your handler runs. Capture the raw bytes before that happens. If you sign JSON.stringify(req.body), the whitespace or field ordering will differ from what we signed and you’ll always fail verification.
String comparison short-circuits on the first differing character — that timing leak lets an attacker brute-force the signature one character at a time. Always use the constant-time comparison helper your platform provides.
Without a timestamp tolerance check, a leaked signature is valid forever. The t= field in the header exists specifically so you can reject replays older than ~5 minutes.
Treat it like any other API credential. Store in your secrets manager, never log it, rotate periodically.