Requex.me LogoRequex.me

Documentation

Browse by section

Keep all guides, tool docs, automation recipes, and comparison pages in one navigable place.

Docs Home
Docs

Foundation docs for getting started fast, understanding key terms, and tracking what has changed.

Guides

Start with fundamentals, then move into provider-specific webhook testing and production hardening.

Tool Docs

These pages explain what each tool does, when to use it, and how it fits into a webhook debugging workflow.

Automation Docs

Use these setup guides when you want forwarding rules, custom responses, security checks, or multi-destination fanout.

Compare

Use these pages to compare developer workflows, pricing tradeoffs, and feature differences between webhook tools.

Webhook Testing in Python

Receive webhooks in Flask or FastAPI, verify HMAC signatures, and debug payloads — complete Python walkthrough with real code examples.

Editorially reviewed by the Requex team11 min readAbout the product

TL;DR: Flask and FastAPI both make great webhook receivers. Read the raw request body before parsing for HMAC verification, return 200 quickly, and offload processing to a background task.

Minimal Flask Webhook Receiver

Flask is a natural fit for webhook handlers — it has minimal boilerplate and gives you direct access to request headers and body. Install with pip install flask and create a single route:

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def handle_webhook():
    event_type = request.headers.get('X-Event-Type')
    payload = request.json
    print(f'Event: {event_type}')
    print(f'Payload: {payload}')
    return jsonify({'received': True}), 200

if __name__ == '__main__':
    app.run(port=5000)

Always return the 200 before doing any slow work. Webhook providers have strict timeout windows (typically 5–30 seconds) and will mark the delivery as failed if you exceed them.

FastAPI Webhook Handler

FastAPI's BackgroundTasks makes it easy to respond immediately and process the event asynchronously in the same process. Install with pip install fastapi uvicorn:

from fastapi import FastAPI, Request, BackgroundTasks
import json

app = FastAPI()

async def process_event(body: bytes):
    data = json.loads(body)
    # Process here...

@app.post('/webhook')
async def webhook(request: Request, background_tasks: BackgroundTasks):
    body = await request.body()
    background_tasks.add_task(process_event, body)
    return {'received': True}

Note that await request.body() returns the raw bytes — which is exactly what you need for HMAC verification before parsing.

HMAC Signature Verification in Python

Most webhook providers sign payloads with HMAC-SHA256. The golden rule: capture the raw body bytes before calling json.loads(). In Flask that means using request.get_data(); in FastAPI use await request.body().

import hmac
import hashlib
import os

def verify_signature(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        raw_body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f'sha256={expected}', signature)

Always use hmac.compare_digest() instead of ==. The standard equality operator short-circuits on the first mismatched character, leaking timing information that an attacker can exploit to brute-force your secret.

Wiring it into a Flask route:

@app.route('/webhook', methods=['POST'])
def handle_webhook():
    raw_body = request.get_data()
    signature = request.headers.get('X-Signature-256', '')
    secret = os.environ['WEBHOOK_SECRET']

    if not verify_signature(raw_body, signature, secret):
        return jsonify({'error': 'Invalid signature'}), 401

    payload = json.loads(raw_body)
    # Process payload...
    return jsonify({'received': True}), 200

Using Requex During Development

Before you implement your Flask or FastAPI handler, point the webhook provider at a Requex.me endpoint. This lets you capture the exact JSON structure the provider sends — including all headers, the signature header name, and the signature format — without running any Python code.

Once you have a captured payload, replay it locally with curl or Python's requests library:

import requests

payload = {"id": "evt_123", "type": "payment.succeeded", "amount": 4900}
response = requests.post(
    'http://localhost:5000/webhook',
    json=payload,
    headers={'X-Event-Type': 'payment.succeeded'}
)
print(response.status_code, response.json())

This workflow means you can iterate on your handler logic without triggering a real event in the provider each time — dramatically speeding up development.

Capture Your First Python Webhook

Get a public endpoint instantly. Inspect headers, raw body, and signatures — no Flask server needed to start.

Open Requex →

Related guides

Start Testing Webhooks Now

Generate your unique URL and test webhooks instantly. Free, no signup.

Open Webhook Tester →