EnglishWebhooksHMAC signature

Signature verification

Every webhook request arrives with:

  • X-Infi-Timestamp: unix timestamp in seconds.
  • X-Infi-Signature: sha256=<hex>, where <hex> is the HMAC-SHA256 computed over the concatenation "{timestamp}.{raw body}" using the webhook secret.

Algorithm

  1. Capture the raw body of the request (bytes, before any JSON parsing).
  2. Capture the X-Infi-Timestamp and X-Infi-Signature headers.
  3. Concatenate: payload = "{timestamp}.{rawBody}".
  4. Compute expected = HMAC-SHA256(WEBHOOK_SECRET, payload) and encode in hex.
  5. Compare "sha256=" + expected with the received header in constant time.
Use the raw body, not re-serialized JSON

The signature is over the exact bytes sent. Re-serializing the JSON on your side can change key order or spacing and break the verification. Configure your framework to preserve the raw body (e.g., in Express use express.raw({ type: 'application/json' })).

Where to get the `WEBHOOK_SECRET`

The secret is delivered together with your API key, through the secure channel agreed with INFI (encrypted email or dashboard). Do not expose it in public source code or logs — store as an environment variable.

Replay mitigation

Recommended: reject webhooks with X-Infi-Timestamp too old (e.g., > 5 minutes). This protects against replay of legitimate webhooks captured in transit.

Examples

# Shell validation — usually delegated to the application language.
# Concept:
#   payload="${TIMESTAMP}.${RAW_BODY}"
#   expected=$(echo -n "$payload" | openssl dgst -sha256 -hmac "$INFI_WEBHOOK_SECRET" | awk '{print $2}')
#   [[ "sha256=$expected" == "$X_INFI_SIGNATURE" ]]