Webhooks — Enabling Real-Time Communication in a Polling-less Environment

Dive into the world of webhooks and learn how they can be used to facilitate real-time updates from your backend to external systems. We'll explore the process of designing, securing, retrying, and debugging webhook systems at scale, with practical examples from Stripe, GitHub, and Slack.

ShareShare

Webhooks — Enabling Real-Time Communication in a Polling-less Environment

In the realm of APIs, the standard model of communication is request-driven. This implies that the client initiates a request, and the server provides an answer. However, this model proves inefficient when the client doesn't know the right time to initiate a request.

To fill this gap, webhooks were introduced.

Webhooks flip the conventional model of communication. Instead of having the client poll the server at regular intervals, the server proactively pushes updates to the client whenever a significant event occurs. This could be anything from a new order placement, user registration, completion of payment, repository push, and much more.

Webhooks are essential for building interconnected systems, facilitating integrations, and delivering a real-time User Experience (UX) without causing unnecessary strain on the infrastructure.


Understanding the Problem that Webhooks Solve

Consider a scenario where a user updates their billing information on Stripe.

In the absence of webhooks, your application would need to:

  • Poll Stripe periodically for any changes
  • Utilize resources unnecessarily when there are no changes
  • Risk missing updates between polling intervals

On the other hand, with webhooks:

  • Stripe automatically sends you a customer.updated event
  • You can process this event immediately
  • The user's profile gets updated with the new billing information in real-time

In essence, webhooks enable systems to notify each other in a timely manner.


Fundamental Concepts of Webhooks

  • Event: This signifies an occurrence (such as user.created, order.shipped)
  • Receiver (consumer): This is your server that receives the event
  • Payload: This is the JSON body containing data about the event
  • Signature: This is a cryptographic hash used to verify the authenticity of the event
  • Retry logic: This is implemented in case the receiver is down or slow

Webhooks typically use:

  • HTTP POST for sending requests
  • JSON payloads for encapsulating data
  • Retries with exponential backoff to handle failed attempts
  • Authentication headers or HMAC signatures for security

Sample Webhook Payload

POST /webhooks/stripe HTTP/1.1
Content-Type: application/json
Stripe-Signature: t=12345,v1=abc,v2=...

{
  "type": "invoice.paid",
  "data": {
    "object": {
      "id": "in_123",
      "amount_paid": 4200
    }
  }
}

In the above example, the HTTP POST request is sent to the /webhooks/stripe route. The payload contains a type field signifying the event and a data field containing the relevant data. The Stripe-Signature in the header is used for verification.


Design Patterns for Webhooks

Webhooks should be designed to be efficient and secure. Here are some design patterns to consider:

  • Use dedicated webhook routes (/webhooks/stripe, /hooks/github) for better organization and security.
  • Response time should be under 1s to avoid timeouts.
  • Queue long-running logic using tools such as Redis, SQS, or background workers to prevent blocking.
  • Log every payload and status for observability and debugging.
  • Implement idempotency to avoid processing the same event multiple times.

💡 Always return 2xx to confirm delivery. The webhook's retry logic depends on this.


Securing Webhooks

Security is paramount when dealing with webhooks. Here are some security measures you can take:

  • ✅ Validate HMAC signatures (e.g., using SHA256 with a secret key) to ensure the authenticity of the event.
  • ✅ Check the User-Agent or custom headers to verify the source of the request.
  • ✅ Enforce IP allowlists for critical systems to prevent unauthorized access.
  • ✅ Reject unexpected payload shapes or events to prevent potential attacks.

Here's how you can verify an HMAC signature using Stripe (Node.js):

const event = stripe.webhooks.constructEvent(
  req.body,
  req.headers['stripe-signature'],
  STRIPE_SECRET
);

Remember, never trust unauthenticated incoming HTTP requests without validation.


Retry Logic and Reliability

A robust webhook system must be prepared for the following scenarios:

  • The consumer might be down or unavailable.
  • Timeouts can occur.
  • Delivery is not guaranteed without retries.

To handle these issues, implement exponential backoff for retries, and make sure to retry for at least 24–72 hours. Additionally, log failures with relevant information such as the status code, time received, body, and headers.

Some platforms like Stripe, GitHub, and Slack provide dashboards to inspect and resend requests.


Webhook Consumers: Best Practices

When consuming webhooks, follow these best practices:

  • Respond with 2xx only after successful processing.
  • Use unique IDs for deduplication to prevent processing the same event multiple times.
  • Write tests for idempotency to ensure consistent behavior.
  • Monitor webhook delivery rate and latency to assess performance.
  • Store event_id or payload hash for traceability in case of issues.

Real-World Examples

Stripe

  • Fires a multitude of event types (payment_intent.succeeded, invoice.failed).
  • Uses HMAC signatures along with secret keys for security.
  • Provides retries and a webhook dashboard for managing and resending requests.

GitHub

  • Sends various types of events such as push events, pull request events, and deployment hooks.
  • Supports secret token signing for security.
  • Allows delivery tracing per event for better management.

Slack

  • Uses incoming/outgoing webhooks for custom integrations.
  • Provides test tools and retry simulation for debugging.
  • Payloads include timestamps, user metadata, and message content for comprehensive event data.

Debugging Webhooks

Several tools can help with debugging webhooks:

Furthermore, log everything in both staging and production environments for better insights into the system's behavior. This includes timestamps, headers, event types, request/response bodies, and retry counts.


Anti-Patterns

While using webhooks, avoid the following anti-patterns:

  • Blocking your application based on webhook success.
  • Not validating the sender's identity.
  • Assuming delivery will only happen once.
  • Ignoring failed retries.
  • Letting failures in 3rd-party webhook systems break internal workflows.

Conclusion: Webhooks Are APIs in Reverse

Webhooks are a powerful tool that make your systems more intelligent. They eliminate guesswork, reduce resource usage, and enable robust integrations across different platforms and teams.

Webhooks should not be an afterthought; they are a core aspect of modern architecture. Design them with the same diligence you would apply to your endpoints:

  • Secure them.
  • Log them.
  • Make them resilient.
  • And most of all — make them useful.

In the world of APIs, we ask for data. But with webhooks, we listen for it.

Subscribe for Deep Dives

Get exclusive in-depth technical articles and insights directly to your inbox.

about

Ehsan Hosseini

Ehsan Hosseini

me [at] ehosseini [dot] info

Staff Software Engineer and Tech Lead with a track record of leading high-performing engineering teams and delivering scalable, end-to-end technology solutions. With experience across web, mobile, and backend systems, I help companies make smart architectural decisions, scale efficiently, and align technical strategy with business goals.

© 2025 Ehsan Hosseini. All rights reserved.