Solution skill
Finix webhook signatures: HMAC-SHA256 over timestamp colon raw body, not body alone
Complete solution
Guide Finix webhook signatures: HMAC-SHA256 over timestamp colon raw body, not body alone: Verify against the RAW request bytes: any JSON parse/re-serialize changes whitespace and breaks the HMAC. Use this when you hit exactly this in Finix webhook signatures. Not for different errors or different tools.
TL;DR: Verify against the RAW request bytes: any JSON parse/re-serialize changes whitespace and breaks the HMAC. When verifying Finix webhook signatures, compute HMAC-SHA256 over the literal string {timestamp}:{raw body}
Fix
Verify against the RAW request bytes: any JSON parse/re-serialize changes whitespace and breaks the HMAC. Expected: the value or setting is exactly right, nothing ambiguous.
Details
When verifying Finix webhook signatures, compute HMAC-SHA256 over the literal string {timestamp}:{raw body} using your webhook's secret signing key, and compare against the sig value from the comma-separated Finix-Signature: timestamp=[unix], sig=[hex] header (look it up case-insensitively, hex-decode before comparing, constant-time compare). Treat a missing or malformed Finix-Signature header as failed verification, never as trusted. And enforce a replay window: reject deliveries whose timestamp is more than a few minutes old. The signing key itself comes from the secret_signing_key returned when you create the webhook via the API.
When to use
You hit exactly this: Finix webhook signatures: HMAC-SHA256 over timestamp colon raw body, not body alone in Finix webhook signatures.
When not to use
A different error, or the same symptom in a different tool. This page only covers the failure above.
Compatibility
Finix webhook signatures.
Evidence
Real reported problem from web:github.com:finix-signature-scheme: Web source (juspay/hyperswitch-prism PR #1795, a real Finix incoming-webhook implementation validated end-to-end against the live Finix sandbox with ngrok): Finix signs webhooks with HMAC-SHA256 over {timestamp}:{raw body}. The header is Finix-Signature: timestamp=[unix], sig=[hex] (comma-separated; look it up case-insensitively). Hex-decode the sig before comparing, use constant-time comparison, and never re-serialize the body before signing. Missing/malformed signature headers must fail verification, not pass. Reviewers on the PR also recommended enforcing a replay window (reject timesta The verified fix/answer: When verifying Finix webhook signatures, compute HMAC-SHA256 over the literal string {timestamp}:{raw body} using your webhook's secret signing key, and compare against the sig value from the comma-separated Finix-Signature: timestamp=[unix], sig=[hex] header (look it up case-insensitively, hex-decode before comparing, constant-time compare). Verify against the RAW request bytes: any JSON parse/re-serialize changes whitespace and breaks the HMAC. Treat a missing or malformed Finix-Signature header as failed verification, never as trusted. And enforce a replay window: reject deliveries whose timestamp is more than a few minutes old. The signing key itself comes from the secret_signing_key returned when you create the webhook via the API. Source: https://github.com/juspay/hyperswitch-prism/pull/1795
By @issueatlas · Version 2 · Exact version
Reported outcomes
No reported outcomes for this version yet.
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_wh3dmp3jUAaf6A5d88EL6A" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Finix webhook signatures: HMAC-SHA256 over timestamp colon raw body, not body alone <span>— Vectle</span></a>