Contact Us

If you still have questions or prefer to get help directly from an agent, please submit a request.
We’ll get back to you as soon as possible.

Please fill out the contact form below and we will reply as soon as possible.

  • Contact Us
Home Webhooks and Real-Time Results Securing Webhooks (HMAC)
In this category
Testing Webhooks Webhook Troubleshooting Webhooks Overview Securing Webhooks (HMAC) Webhook Payload Structure & Event Types
Related
Testing Webhooks Webhook Troubleshooting Webhooks Overview Webhook Payload Structure & Event Types

Securing Webhooks (HMAC)

Understand how the webhooks are secured at each end point.

Updated April 14th, 2026

Overview

Every webhook Begini sends includes an X-Signature header containing an HMAC SHA-512 hash of the raw request body, generated using your API key as the secret. You must verify this signature before processing any payload.

Skipping verification means your endpoint will accept forged or tampered requests.

How it works

  1. Begini generates the JSON payload
  2. Begini hashes the raw payload body using your API key with HMAC SHA-512
  3. The hash is sent in the X-Signature request header
  4. Your server receives the request, reads the raw body, and generates the same hash independently
  5. You compare your hash against the X-Signature value — if they match, the request is genuine

Request headers

X-Signature: <hmac_sha512_hexdigest>
Content-Type: application/json

Implementation

Critical: use the raw request body

You must hash the raw request body exactly as received — before any JSON parsing. Any modification (reformatting, whitespace changes, re-serialisation) will produce a different hash and verification will fail.

Python (FastAPI)

import hashlib
import hmac
from fastapi import APIRouter, Request, HTTPException, status

router = APIRouter()

@router.post('/webhook-receiver')
async def receive_webhook(request: Request):
    payload = await request.body()
    signature_from_request = request.headers.get("X-Signature")
    expected_signature = hmac.new(
        '<YOUR_API_KEY>'.encode('utf-8'),
        payload,
        digestmod=hashlib.sha512
    ).hexdigest()

    if not hmac.compare_digest(expected_signature, signature_from_request):
        raise HTTPException(status_code=403, detail='Validation Failure')

    return status.HTTP_200_OK

Python (manual verification)

import hmac
import hashlib

def verify_webhook(raw_body: bytes, received_signature: str, api_key: str) -> bool:
    expected = hmac.new(
        api_key.encode('utf-8'),
        raw_body,
        digestmod=hashlib.sha512
    ).hexdigest()
    return hmac.compare_digest(expected, received_signature)

Always use hmac.compare_digest for the comparison — this performs a constant-time comparison and prevents timing attacks. Do not use ==.

Common mistakes

Mistake Effect
Parsing JSON before hashing Different hash, verification always fails
Using the wrong API key (Test vs Production) Verification fails in one environment
Using == instead of compare_digest Timing attack vulnerability
Ignoring verification failures Forged requests processed

If verification fails

Return a non-200 response (e.g. HTTP 403), do not process the payload, and log the failure for investigation. Never silently accept a request that fails verification.

Additional security measures

HMAC verification should be combined with:

  • HTTPS-only endpoints
  • IP whitelisting (contact your account manager for Begini's IP ranges)
  • Rate limiting on your receiver endpoint
  • Secure storage of your API key

Next steps

  • Testing Webhooks — validate your endpoint using the test API
  • Webhook Troubleshooting — diagnose delivery and processing issues
  • Security Checklist — full pre-launch security checklist

Was this article helpful?

Yes No
Give feedback
Begini Logo_white

SaaS technology that provide character-based credit scores for Banks, Micro Finance, Digital Lenders, Neo Banks, BNPL and Asset Financing.

About

  • About Us
  • Contact Us
  • Privacy Policy

Solutions

  • Device Data
  • Psychometrics

Resources

  • Support
  • Blog
Linkedin Twitter Medium Youtube

© All rights reserved

GPDR compliant white
Expand