Python Webhook Handlers — Core Concepts
Why this matters
Webhooks are the backbone of modern service integration. When your Python application needs to react to events in external services — payments processed in Stripe, commits pushed to GitHub, messages received in Slack — webhooks provide real-time notification without polling. Almost every SaaS API offers webhooks, and building reliable handlers is a core backend skill.
The difference between polling and webhooks is significant at scale: polling 1,000 times to catch 3 events wastes 997 API calls. A webhook delivers exactly 3 requests.
How webhooks work
The flow has four stages:
- Registration — You tell the external service “Send events to this URL” (either through their dashboard or API). This URL must be publicly accessible over HTTPS.
- Event occurs — Something happens in the external service (payment succeeds, file uploaded, user signs up).
- Delivery — The service sends an HTTP POST request to your URL with event details in the request body (usually JSON).
- Processing — Your webhook handler receives the request, verifies it is authentic, processes the event, and returns a 200 response.
Anatomy of a webhook request
A typical webhook POST contains:
| Component | Purpose |
|---|---|
| HTTP method | Always POST |
| URL | Your registered endpoint |
| Headers | Content-Type, signature header, event type |
| Body | JSON payload with event data |
| Signature | HMAC hash proving the request is genuine |
The signature header is critical. Without it, anyone who discovers your webhook URL could send fake events.
Signature verification
Most services sign webhook payloads using HMAC-SHA256. They share a secret key with you during registration, then include a signature in each request header computed from the raw request body and the shared secret.
Your handler must:
- Read the raw request body (before JSON parsing).
- Compute the expected HMAC using the shared secret.
- Compare it to the signature in the header.
- Reject the request if they do not match.
This prevents attackers from forging webhook requests.
Idempotency
Webhook providers retry delivery when they do not receive a 200 response (network timeout, server error). This means your handler might receive the same event multiple times. Building idempotent handlers — ones that produce the same result regardless of how many times they process the same event — is essential.
The standard approach: store the event ID after processing, and check for it before processing new events. If the ID already exists, skip processing and return 200.
Response expectations
Webhook providers expect a fast response:
- Return 200 (or 2xx) to acknowledge receipt.
- Respond within 5-30 seconds (varies by provider).
- If processing takes longer, accept the webhook immediately and process it asynchronously via a task queue.
Returning a 4xx or 5xx status, or timing out, triggers retries — which can overwhelm your server if the underlying problem is not fixed.
Common misconception
“Webhook handlers should process the event inline before responding.” For anything beyond trivial processing, this is risky. If your handler takes 10 seconds to update a database, call another API, and send an email, any timeout or error means the webhook provider retries, potentially causing duplicate processing. The reliable pattern is: verify the signature, store the raw event, return 200 immediately, then process asynchronously.
Event types and routing
Most services send different event types to the same endpoint. Your handler needs to route them:
| Event type | Action |
|---|---|
payment.succeeded | Fulfill order |
payment.failed | Notify customer |
customer.created | Send welcome email |
subscription.cancelled | Revoke access |
An event type field in the payload (or a header) tells your code which handler function to run.
One thing to remember: A reliable webhook handler does three things fast: verifies the signature, stores the event for idempotent processing, and returns 200. Everything else happens asynchronously — keeping your endpoint responsive and your integrations trustworthy.
See Also
- Python Api Rate Limit Handling Why APIs tell your Python program to slow down, and how to handle it gracefully — explained so anyone can follow along.
- Python Proxy Rotation Why Python programs disguise their internet address when collecting data, and how proxy rotation works — explained without any tech jargon.
- Python Sse Client Consumption How Python programs listen to live data streams from servers — like a radio that never stops playing — explained for complete beginners.
- Python Web Scraping Ethics When is it okay to collect data from websites with Python, and when does it cross the line? The rules explained for everyone.
- Ci Cd Why big apps can ship updates every day without turning your phone into a glitchy mess — CI/CD is the behind-the-scenes quality gate and delivery truck.