The Webhook Trade-Off
Webhooks have been a staple of the API world since Jeff Lindsay coined the term in 2007. Conceived as a general-purpose "hook" for the web, they allow Internet systems to be composed in the spirit of the Unix pipe. By speaking HTTP and mirroring the symmetry of common HTTP APIs, webhooks filled a gap at a time when WebSockets were still years from standardization and other streaming options were barely on the horizon.
For platforms like GitHub, Slack, and Stripe, webhooks remain one of the most recognizable features. They are reliable, support multiple receivers with customized event sets, and work with OAuth-connected accounts, enabling downstream platforms to react to user activity. But the pattern has genuine shortcomings. It is worth examining whether webhooks are a model new API providers should emulate or avoid.
Why Webhooks Appeal
REST APIs handle access and manipulation of resources, but they are weak at real-time delivery. Webhooks fill that gap by streaming updates as they happen, which is a considerable improvement over polling.
Consider a simple CI service that builds pull requests. With only a REST API, the service would poll GitHub's status endpoints every few seconds to detect new pull requests. By listening for the pull_request webhook instead, the service gets notified the moment anything changes, then uses the REST API to set a pending status and update it when the build finishes.
Users see the status check appear immediately, with no polling overhead.
User-Side Friction
The developer experience of consuming webhooks is not always smooth.
Endpoint Provisioning and Management
Receiving a webhook requires an HTTP endpoint reachable from the public Internet. In many organizations, that is a bureaucratic hurdle. Large enterprises often need to negotiate with infrastructure and security teams, requisition hardware, and complete paperwork before exposing a new endpoint. In some cases, webhooks are entirely incompatible with security policies that require user data to remain inside a secured perimeter at all times.
Even for smaller setups, local development is awkward. Ngrok and similar tunneling tools work, but they introduce extra steps and complexity that a synchronous API would not require.
Security Is Up to the Consumer
Because webhook endpoints are public HTTP APIs, providers must design a security scheme so attackers cannot forge payloads. Common techniques include:
- Webhook signing: The provider signs the payload and includes the signature in an HTTP header so the consumer can verify it.
- HTTP authentication: The consumer must supply HTTP basic auth credentials when configuring the endpoint.
- API retrieval: The webhook contains only an event identifier, and the consumer must make a synchronous API request to fetch the full message content.
Of these, only API retrieval guarantees strong security. Providers can sign payloads, but cannot verify that consumers actually check the signatures. If basic auth is required, many users will choose weak credentials, and because endpoints typically have no rate limiting, they are vulnerable to brute-force attacks. This contrasts sharply with synchronous APIs, where the provider controls key format, issuance, and rotation practices.
Testing and Development
Stubbing a synchronous API is straightforward. Testing webhooks is not, because the user needs a way to trigger test deliveries. Stripe offers a "Send test webhook" button in its dashboard, which helps but is manual and poor for automated test suites.
Manual testing is insufficient for long-term reliability. Without CI coverage, a working integration tends to drift until something breaks.
No Ordering Guarantees
Webhooks are usually sent in order, but transmission failures, latency variation, and provider quirks mean there are no strict guarantees. A created event for resource123 may fail and get queued for retransmission while a deleted event for the same resource goes out normally. When the retry eventually lands, the consumer receives events out of order and must tolerate the discrepancy.
A truly reliable stream would behave like an ordered append-only log that consumers could use to manage database state. Webhooks are not that system.
Version Upgrades Are Awkward
API versioning is manageable when clients explicitly request a version with each call. Webhooks put the provider in the position of deciding which version to send. Consumers end up writing code that tries to handle multiple versions, then flip the upgrade switch and hope for the best. When it fails, they roll back. Stripe now lets users configure the API version per webhook endpoint, but for many providers and for a long time, upgrades have been a cumbersome process.
The Provider Burden
Running a webhook system is harder than it looks, and much of the operational weight falls on the provider, not the consumer.
Misbehaving Consumers
When a consumer endpoint slows down or begins rejecting requests, it puts pressure on the provider's delivery infrastructure. A large user generating millions of webhooks can back up global queues and degrade the entire system. The provider bears the burden of chasing users whose endpoints are failing, sending messages like "please fix your systems or we will have to disable you." SLAs or uptime requirements can mitigate this, but they need tooling, documentation, and will frustrate some users.
Retry Policy Overhead
Reliable delivery requires retries, but the cost at the margins is significant. If a user deletes a server without removing the endpoint, Stripe will attempt redelivery 72 times — once an hour for three days — potentially wasting tens of thousands of connections. Disabling dead endpoints helps, but then there are "living dead" endpoints that time out most requests after tying up clients for 30 seconds, yet succeed often enough to never get disabled. Supporting those is expensive.
Chatty by Design
Each webhook is one HTTP request for one event. Keeping connections alive helps reduce the overhead of connection setup and TLS negotiation for frequent deliveries, but the protocol remains inherently chatty when compared to streaming thousands of events over a single firehose connection.
Internal Security Risks
Webhook senders live inside the provider's infrastructure. If they are not isolated from other internal services, an attacker can probe internal network addresses by configuring a webhook endpoint with an internal URL. Mitigations exist, and major providers have measures in place, but webhook infrastructure is dangerous by default and must be carefully insulated.
Why Webhooks Still Work
Webhooks have drawbacks, but their advantages are equally real. Two properties in particular make them hard to beat in practice.
Implicit Load Balancing
One underappreciated benefit: webhooks give you automatic load balancing and allow consumer traffic to ramp up gradually. A “pull” API that streams events over a single connection works up to a point, but at sufficient volume you inevitably need a partitioning scheme like the ones in Kafka or Kinesis. Partitions are workable but add complexity and friction; getting consumers to move from one partition to two when they hit the ceiling is genuinely hard.
Webhooks avoid that migration entirely. Recipients only need to scale their endpoints horizontally behind a standard load balancer — DNS, HAProxy, ELBs — which is a well-understood problem.
Universal Reach
Web servers exist in every programming language and framework, which means anybody can receive a webhook without pulling in exotic dependencies. That accessibility has real value: a larger pool of developers can integrate, which leads to more integrations. GitHub and Slack both grew their platforms on exactly that ease of use.
Modern Alternatives
The webhook model has been around long enough that newer streaming technologies have emerged that address some of its weaknesses.
The HTTP Log
WebSockets and server-sent events (SSE) both let a consumer negotiate a stream over HTTP and listen for incoming events. Unlike webhooks, events are available from any environment that permits outgoing connections, are fully verifiable, arrive in order, and can be versioned per the consumer’s request.
The tradeoff is that consumers must track their own position and resume correctly after disconnects. Some users will inevitably lose their place or fail to consume fast enough. Providers must also cap how far back consumers can replay and build efficient storage for aging event data.
GraphQL Subscriptions
GraphQL defines a third operation type beyond queries and mutations: subscriptions. The provider exposes a subscription describing the events a recipient can receive, plus an input type for stream parameters. Implementation specifics remain loose, as with much of GraphQL — Facebook’s announcement described receiving subscription events over an MQTT topic, but other pub/sub technologies work as well.
gRPC Streaming RPC
gRPC, Google’s RPC framework built on protocol buffers, supports server-streaming RPCs in addition to one-off request/response calls. A server can send any number of messages before closing the connection, and bi-directional streaming is available for two-way communication over a single reused connection. The feature spans gRPC’s broad set of supported languages.
The Practical Takeaway
Webhooks remain a solid real-time delivery system, and providers that already run them operationally should probably stay the course. They work and developers understand them.
For new APIs, though, the calculus is different. Between the developer experience gaps and operational overhead, every option deserves consideration. Teams already on non-REST paradigms like GraphQL or gRPC have a clear path forward. Everyone else might do well modeling something like a log over HTTP, WebSockets, or SSE.



