Understanding the difference between webhooks and APIs is crucial for building efficient, real-time applications.
API (Application Programming Interface)
Definition: A request-response model where the client actively requests data from the server.
How APIs Work (Pull Model)
sequenceDiagram
participant Client
participant Server
loop Every 5 minutes
Client->>Server: GET /api/orders
Server->>Client: Response (orders data)
end
API Example (REST)
// Client makes request
GET https://api.example.com/users/123
// Server responds
{
"id": 123,
"name": "John Doe",
"email": "john@example.com"
}
Webhook
Definition: An event-driven model where the server automatically sends data to the client when an event occurs.
How Webhooks Work (Push Model)
sequenceDiagram
participant Server
participant Client
Note over Server: Event occurs (e.g., new order)
Server->>Client: POST /webhook/orders
Note over Server: Sends event data
Client->>Server: 200 OK
Webhook Example
// Server sends POST request to client's webhook URL
POST https://your-app.com/webhook/payment
{
"event": "payment.success",
"payment_id": "pay_123",
"amount": 99.99,
"timestamp": "2024-01-15T10:30:00Z"
}
Key Differences
| Aspect | API | Webhook |
|---|---|---|
| Model | Pull (Request-Response) | Push (Event-Driven) |
| Initiator | Client | Server |
| Timing | On-demand | Real-time (when event occurs) |
| Efficiency | May poll unnecessarily | Only sends when needed |
| Use Case | Fetching data on demand | Real-time notifications |
Implementing a Webhook
Node.js Example
const express = require('express');
const app = express();
app.use(express.json());
// Webhook endpoint
app.post('/webhook/github', (req, res) => {
const event = req.headers['x-github-event'];
const payload = req.body;
console.log(`Received ${event} event`);
if (event === 'push') {
console.log(`New push to ${payload.repository.name}`);
console.log(`Commits: ${payload.commits.length}`);
}
res.status(200).send('Webhook received');
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
C# Example (ASP.NET Core)
[ApiController]
[Route("webhook")]
public class WebhookController : ControllerBase
{
[HttpPost("stripe")]
public IActionResult StripeWebhook()
{
var json = new StreamReader(HttpContext.Request.Body).ReadToEnd();
var stripeEvent = EventUtility.ParseEvent(json);
switch (stripeEvent.Type)
{
case "payment_intent.succeeded":
var paymentIntent = stripeEvent.Data.Object as PaymentIntent;
Console.WriteLine($"Payment succeeded: {paymentIntent.Id}");
break;
case "payment_intent.payment_failed":
Console.WriteLine("Payment failed");
break;
}
return Ok();
}
}
Webhook Security
1. Signature Verification
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Usage
app.post('/webhook', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process webhook
res.status(200).send('OK');
});
2. IP Whitelisting
const allowedIPs = ['192.168.1.100', '10.0.0.50'];
app.post('/webhook', (req, res) => {
const clientIP = req.ip;
if (!allowedIPs.includes(clientIP)) {
return res.status(403).send('Forbidden');
}
// Process webhook
res.status(200).send('OK');
});
3. HTTPS Only
- Always use HTTPS for webhook endpoints
- Prevents man-in-the-middle attacks
- Encrypts sensitive payload data
Real-World Examples
GitHub Webhooks
- Push events: Trigger CI/CD pipelines
- Pull request events: Run automated tests
- Issue events: Update project management tools
Stripe Webhooks
- payment_intent.succeeded: Fulfill order
- customer.subscription.deleted: Cancel access
- invoice.payment_failed: Send reminder email
Twilio Webhooks
- SMS received: Process incoming messages
- Call completed: Log call duration
- Message status: Track delivery
When to Use Each
Use APIs When:
- You need data on-demand
- Client controls timing
- Fetching historical data
- Performing CRUD operations
Use Webhooks When:
- Real-time notifications needed
- Event-driven architecture
- Reducing polling overhead
- Server-to-server communication
Use Both Together
graph LR
Client[Client App]
API[REST API]
Webhook[Webhook Endpoint]
Server[Server]
Client -->|GET /orders| API
API -->|Response| Client
Server -->|POST /webhook/new-order| Webhook
Webhook -->|Notify| Client
Example: Use API to fetch initial data, then use webhooks to receive real-time updates.
Best Practices
- Idempotency: Handle duplicate webhook deliveries gracefully
- Retry Logic: Implement exponential backoff for failed deliveries
- Logging: Log all webhook events for debugging
- Timeouts: Respond quickly (< 5 seconds) to avoid retries
- Validation: Always verify webhook signatures