If you have worked with APIs, you have probably heard statements like:
- “Configure a webhook endpoint”
- “Stripe will send a webhook.”
- “GitHub triggers a webhook on every push.”
Many developers treat webhooks as something special or magical.
They are not.
In fact, understanding webhooks becomes much easier once you realizes one simple fact:
A webhook is not a new technology. It is simply an HTTP endpoint whose purpose is to receive event notification from another system.
Everything else – security, retries, signatures, idempotency, queues – is built around making that communication reliable.
Understanding the Problem
Imagine you own an e-commerce website.
Customers pay using Stripe.
When the payment succeeds, your website should:
- Mark the order as paid.
- Generate an invoice.
- Send an email.
- Start shipping.
The problem is:
How does your application know that the payment succeeded?
There are two possible approaches.
Approach 1: Keep Asking (Polling)
Your server repeatedly asks Stripe:
Has payment succeeded?
No.
...
Has payment succeeded?
No.
...
Has payment succeeded?
Yes.This is called polling.
Your application continuously requests information whether or not anything has changed.
This works.
But it has several drawbacks:
- Wastes API requests
- Higher server load
- Delayed updates
- More network traffic
- Poor scalability
Approach 2: Let Stripe Notify You
Instead of asking repeatedly:
Your Server
(waiting...)
Stripe
Payment Successful
↓
Immediately sends notificationNow your server doesn't need to ask.
Stripe tells your server exactly when something happens.
This is the core idea behind webhooks.
In other words, webhooks enable one system to push information to another in real time, eliminating the need for the receiving application to continuously pull for updates.
Polling vs Webhooks
Imagine ordering pizza.
Polling:
You call every minute.
Is my pizza ready?
No.
One minute later...
Is it ready?
No.
One minute later...
Ready?
No.Webhook
The restaurant calls you.
Pizza Ready
↓
Restaurant calls you immediatelyThe restaurant initiates the communication.
That's exactly how webhooks work.
What Exactly is a Webhook?
Here's the definition that many developers eventually arrive at after building production systems:
A webhook is an HTTP endpoint exposed by an application whose purpose is to receive event notifications from another system.
Notice something important.
The definition does not say:
- a special protocol
- a new networking technology
- a new API type
Because it isn't. It is simple an endpoint.
Webhooks Are Just HTTP Endpoints
This is probably the biggest misconception.
People imagine webhooks as something fundamentally different.
They are not.
Consider Express.js:
app.post("/api/orders", createOrder);
app.post("/webhooks/stripe", stripeWebhook);Express doesn't know which one is a webhook.
Both are simply routes.
The framework treats them identically.
The only difference is who calls them.
Normal API Endpoint
Usually called by:
- frontend
- mobile app
- another internal service
Example:
POST /api/loginThe client decides when to call.
Webhook Endpoint
Usually called by:
- Stripe
- GitHub
- Shopify
- Slack
- PayPal
- Twilio
Example:
POST /webhooks/stripeThe third-party service decides when to call.
That is the difference.
The intention is different – not the technology.
Anatomy of a Webhook
Every webhook consists of four parts.
Let's understand each one.
Event
Something happens.
Examples:
payment.success
payment.failed
order.created
repository.push
user.createdThe event occurs inside another application.
Sender
The application that detected the event.
Examples:
- Stripe
- GitHub
- Shopify
It prepares an HTTP request.
Payload
The event data.
Example:
payment.success
payment.failed
order.created
repository.push
user.createdReceiver
Your webhook endpoint.
Example:
POST /webhooks/paymentThis endpoint receives the request and processes it.
How Do Webhooks Work?
The webhooks are surprisingly simple to understand once you see the flow.
1 Register a webhook endpoint
The receiving application starts by creating an HTTP endpoint (commonly called a webhook endpoint) and sharing its URL with the provider.
For example, you might tell Stripe:
“Whenever a payment succeeds, send the event details to
https://myapp.com/webhooks/payment”
This is essentially your application saying, “Notify me whenever this event happens”.
2 An event occurs
Whenever the subscribed event takes place – for example, a successful payment in Stripe or a new pull request on GitHub – the provider detects the event and prepares an HTTP POST request.
The request contains a payload, typically in JSON format, with all the relevant details about what happened.
3 The webhook is delivered
The provider immediately sends the HTTP POST request to your webhook endpoint. At this point it's essentially saying:
“An event just occurred. Here's everything you need to know.”
Because the provider initiates the request, your application doesn't have to keep checking whether anything has changed.
4 Your application processes the event
Your webhook endpoint receives the request, reads the payload, and performs whatever actions are required.
Depdending on your application's needs, it might:
- Update the database
- Change an order's status
- Send a confirmation email
- Trigger a CI/CD pipeline
- Notify a Slack channel
- Start another business workflow
Once the processing is complete, your application usually responds with a HTTP 200 OK status code to let the provider know the event was received successfully.
The entire process typically completes within seconds — or even milliseconds.
A real-world example
Suppose you are monitoring a GitHub repository.
When someone opens a pull request, GitHub instantly sends a webhook request containing details about the new pull request to your application.
Your service can then automatically trigger a CI/CD pipeline, assign reviewers, or send a notification to Slack – all without anyone manually checking GitHub for updates.
Complete Lifecycle of a Webhook
Let's follow a payment.
Step 1
Customer clicks:
PayStep 2
Stripe processes payment.
SUCCESSStep 3
Stripe creates an event.
payment.successStep 4
Stripe sends HTTP request.
POST /webhooks/stripeBody:
{
"event": "payment.success",
"payment_id": "pay_123"
}Step 5
Your server receives it.
Receive Request
↓
Validate
↓
Process
↓
Return 200Done.
That's literally the webhook lifecycle.
Inside the Webhook Endpoint
A production webhook endpoint usually performs these steps.
Receive Request
↓
Authenticate Sender
↓
Validate Payload
↓
Check Idempotency
↓
Execute Business Logic
↓
RespondLet's understand each one.
Step 1 – Receive Request
The HTTP server receives a POST request.
Exactly like every other API endpoint.
Nothing special happens here.
Step 2 – Authenticate the Sender
Anyone on the internet could send:
POST /webhooks/stripeWithout authentication, attackers could fake events.
Therefore we verify the sender.
Common techniques:
- HMAC signature
- Shared secret
- Timestamp verification
- IP allow-list (optional)
Step 3 – Validate Payload
Never assume incoming data is correct.
Verify:
- required fields
- event type
- data types
- schema
Example:
Missing payment_id
↓
Reject requestStep 4 – Check Idempotency
One event may arrive multiple times.
This surprises many beginners.
Webhooks are at least once delivered.
That means duplicates are normal.
Suppose Stripe retries.
payment.success
↓
payment.success
↓
payment.successShould you process all three?
No.
Instead:
event_id
↓
Already processed?
↓
Yes
↓
IgnoreThis property is called idempotency.
An idempotent operation produces the same result whether executed once or many times.
Step 5 – Execute Business Logic
Only after validation should business logic execute.
Example:
Update Order
↓
Generate Invoice
↓
Send Email
↓
Notify WarehouseStep 6 – Respond
Return success.
HTTP 2000 OKThis tells the sender:
Delivery SuccessfulWebhook Security
Security is where production systems differ from tutorials.
Signature Verification
Most providers compute:
signature = HMAC(secret, request_body)They include it in headers.
X-Signature
abc123...Your server calculates the same value.
If they match:
ValidOtherwise:
RejectThis prevents forged requests.
Timestamp Validation
Suppose someone records a legitimate webhook.
Six months later they replay it.
Without timestamp validation:
Old Payment
↓
Processed AgainTimestamp verification prevents replay attacks.
HTTPS
Always use HTTPS.
Never expose webhook endpoints over HTTPS.
Validate Everything
Never trust incoming payloads.
Validate:
- types
- schema
- required fields
- supported event names
Why Webhooks Are Retried
Network fail.
Server crash.
Databases become unavailable.
Suppose your server responds:
500 Internal Server ErrorShould Stripe give up?
No.
Instead:
Attempt 1
↓
Fail
↓
Wait
↓
Attempt 2
↓
Fail
↓
Attempt 3Most providers implement exponential backoff.
Example:
1 minute
↓
5 minutes
↓
30 minutes
↓
2 hoursWhy Idempotency Is Critical
Imagine:
Payment
↓
Webhook arrives
↓
Order marked paidNow suppose the response times out.
Stripe never receives:
200 OKStripe assumes delivery failed.
It retries.
Same Event AgainWithout idempotency:
Charge Customer Again
Generate Invoice Again
Ship AgainA disaster.
Therefore:
event_id
↓
Already Exists?
↓
IgnoreIdempotency is mandatory.
Why Queues Matter
Beginners often write:
Receive Webhook
↓
Update Database
↓
Generate PDF
↓
Resize Images
↓
Send Email
↓
Call Another API
↓
Return 200This is bad.
The sender waits.
Instead.
Receive Webhook
↓
Validate
↓
Store Event
↓
Push to Queue
↓
Return 200 ImmediatelyWorker processes later.
Queue
↓
Worker
↓
Email
↓
Database
↓
ReportsBenefits:
- Fast responses
- Better scalability
- Higher reliability
- Retry support
- Fault isolation
Full Mental Model
An event occurs in a third-party system
│
▼
The third party creates an event payload
│
▼
It sends an HTTP POST request to your webhook endpoint
│
▼
Your endpoint:
• Verifies the sender
• Validates the payload
• Checks idempotency
• Records or queues the event
│
▼
Background workers execute the business logic
│
▼
Your application updates its stateLeave a comment
Your email address will not be published. Required fields are marked *


