Python

Webhooks Explained: How They Work and Why They Matter

Learn what webhooks are, how they replace inefficient polling with real-time notifications, and how to build a secure webhook endpoint in Python with Flask.

August 2026 6 min read 18 views 0 hearts

Webhooks are the quiet workhorses of modern software. While APIs are the clerks you ask for data, webhooks are the messengers that knock on your door the second something happens. If you've ever seen a Slack notification pop up the moment a payment clears, or a GitHub action trigger the second someone pushes code, you've watched webhooks do their thing.

But how do they actually work? And why are they suddenly everywhere? Let's break it down without the jargon.

The Polling Problem

Before webhooks became mainstream, if you wanted to know whether something changed, you had to ask. Constantly. Your system would ping an API every few seconds or minutes, hoping to catch a change. That's called polling, and it's wasteful.

Imagine calling a restaurant every 30 seconds to ask if your table is ready. Frustrating for you, annoying for the staff, and a huge waste of everyone's time. That's exactly what old-school integrations felt like.

Polling works for some things, but it's slow, inefficient, and creates unnecessary load on servers. You're asking "is it done yet?" when you could just wait for a call.

Enter the Webhook

A webhook flips the script. Instead of you asking, the server tells you. It's a reverse API — the provider sends an HTTP POST request to a URL you specify, the moment an event occurs.

Here's the simplest real-world example:

You set up a webhook URL on your server, like https://yoursite.com/webhook/payment. You register that URL with Stripe. Now, every time a customer pays, Stripe sends a JSON payload to that endpoint instantly. No polling. No delays. Just a direct, real-time notification.

The whole flow is:

  1. You register a callback URL with the service.
  2. Something happens (a payment, a new subscriber, a file upload).
  3. The service sends an HTTP request to your URL with the event details.
  4. Your server processes the data and does whatever needs doing.

That's it. The magic is in the timing. Instead of checking every minute, you're reacting within milliseconds.

The Anatomy of a Webhook Payload

Webhooks aren't a standard like REST, but most follow a similar pattern. The payload is usually JSON, and it contains three key things:

  • Event name – What happened? (payment.succeeded, user.created, repo.pushed)
  • Timestamp – When did it happen?
  • Data – The actual details (customer ID, amount, commit hash, etc.)

Here's a stripped-down example of what Stripe sends when a charge succeeds:

{
  "id": "evt_1J2abc123",
  "event": "charge.succeeded",
  "data": {
    "amount": 4999,
    "currency": "usd",
    "customer": "cus_Qwerty123",
    "receipt_email": "buyer@example.com"
  },
  "created": 1712345678
}

Your webhook endpoint receives this, validates it, and does the next step — maybe updating your database, sending a thank-you email, or triggering a fulfillment order.

Why Webhooks Are So Powerful

The big win is real-time efficiency. You get data the instant it exists, not the moment you remember to check. That opens doors to:

  • Live dashboards – Update a customer's order status instantly instead of on a 60-second refresh.
  • Event-driven automation – When a new user signs up, automatically create their account, send a welcome email, and log the activity — all without human input.
  • Reduced server load – Your systems only work when there's actual work, not on a constant polling schedule.

For example, at PythonSkillset, if you ran a subscription service, you wouldn't want your billing system chasing every customer's payment status. You'd let Stripe call your webhook the moment a payment fails, and then you'd send a "Hey, your card was declined" email — instantly.

The Hidden Complexity: Reliability

Webhooks are great, but they're not a fire-and-forget system. If your server is down when the webhook fires, the event could be lost forever. That's why reliable implementations need:

  • Retry logic – Most providers retry failed deliveries (often with exponential backoff).
  • Logging – Every incoming webhook should be logged for debugging.
  • Idempotency – If a webhook is delivered twice, your system shouldn't double-process it. You check the event ID and skip if you've already handled it.

The painful truth is that webhooks fail. Networks drop, timeouts happen, servers crash. A mature webhook consumer handles these edge cases gracefully — not just the happy path.

Building a Webhook Endpoint in Python

Let's make this real with code. Here's a minimal Flask app that receives Stripe webhooks:

from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)
STRIPE_SECRET = b'whsec_your_webhook_secret'

@app.route('/webhook/payment', methods=['POST'])
def handle_payment():
    payload = request.get_data()
    sig_header = request.headers.get('Stripe-Signature')

    # Verify the signature (don't skip this in production!)
    try:
        expected = hmac.new(STRIPE_SECRET, payload, hashlib.sha256).hexdigest()
        # Compare with sig_header (simplified — Stripe uses a timestamp scheme)
        if not hmac.compare_digest(sig_header, expected):
            return jsonify({'error': 'Invalid signature'}), 400
    except Exception:
        return jsonify({'error': 'Verification failed'}), 400

    event = request.json
    event_type = event['type']
    print(f"Received event: {event_type}")

    if event_type == 'payment_intent.succeeded':
        # Do your post-payment logic here
        pass

    return jsonify({'received': True}), 200

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

Notice the signature verification — this isn't optional. Anyone can hit your URL with fake events. Without checking the HMAC signature, you'd be trusting unverified data, which is a security hole the size of a barn door.

Real-World Use Cases That Make Sense

Webhooks shine when speed matters:

  • Payment processing – Update order status instantly when money moves.
  • CI/CD pipelines – When a developer pushes code, automatically start builds and tests.
  • Chat integrations – Slack, Discord, and Teams all support incoming webhooks so services can push notifications directly into channels.
  • IoT devices – A sensor detects movement and sends a webhook to your alarm system.

Each of these has the same theme: something important just happened, and you need to react now.

When Webhooks Aren't the Answer

Webhooks aren't perfect. If you need a complete snapshot of current state (like "list all my customers"), you still use a regular API. Webhooks are for events, not state. Also, if you operate behind a strict firewall that blocks inbound connections, receiving webhooks becomes a problem — you'd need to use a service like a webhook relay or tunnel.

And remember, webhooks are push-based. If you don't process the data fast enough, events queue up. That's fine for low volume, but you might need a job queue for heavy traffic.

Final Thoughts

Webhooks quietly power the real-time web. They're simple to understand but require careful implementation to do right. The core lesson is this: stop asking, start listening. When you design your next integration, ask yourself — does this need to be real-time? If yes, a webhook is probably your answer.

Once you've built one webhook endpoint, you'll see the pattern everywhere. And you'll never want to go back to polling again.

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.