Implementing Webhooks
1. Designing Webhook Payload Structure
Example: Webhook Payload
{
"id": "evt_abc123",
"type": "order.completed",
"createdAt": "2026-05-15T10:30:00Z",
"apiVersion": "2026-01-01",
"data": {
"orderId": 100,
"amount": 250.00,
"currency": "USD"
}
}
| Field | Purpose |
id | Unique event ID for dedup |
type | Event name (dot-notation) |
createdAt | Event time |
apiVersion | Schema version |
data | Event payload |
2. Implementing Webhook Registration
Example: Register Webhook
POST /webhooks
{
"url": "https://client.example.com/hooks",
"events": ["order.created", "order.completed"],
"secret": "auto-generated-or-client-supplied",
"active": true
}
3. Implementing Event Filtering
| Filter Type | Example |
| Event type | events: ["order.*"] |
| Resource attributes | filter: {currency: "USD"} |
| Account scope | Per-tenant subscriptions |
4. Securing Webhooks
| Mechanism | Implementation |
| HMAC signature | Header: X-Signature: sha256=... |
| Timestamp + replay window | Reject if >5 min old |
| HTTPS only | Reject http:// URLs at registration |
| IP allowlist | Optional second factor |
| mTLS | Mutual cert auth (enterprise) |
Example: HMAC Verification (Java)
String expected = "sha256=" + hmacSha256(payload, secret);
if (!MessageDigest.isEqual(
expected.getBytes(),
request.getHeader("X-Signature").getBytes())) {
return ResponseEntity.status(401).build();
}
5. Implementing Retry Logic
| Setting | Typical |
| Max attempts | 5-10 |
| Success | 2xx within 30s |
| Retry on | 5xx, 408, 429, network errors |
| Skip on | 4xx (except 408, 429) |
6. Using Exponential Backoff
| Attempt | Delay |
| 1 | Immediate |
| 2 | 1 min |
| 3 | 5 min |
| 4 | 30 min |
| 5 | 2 hours |
| 6+ | Up to 24 hours |
Note: Add jitter (±20%) to avoid thundering herd.
7. Implementing Webhook Timeouts
| Setting | Value |
| Connection timeout | 5s |
| Read timeout | 30s (Stripe), 10s (GitHub) |
| Total budget | Document explicitly |
8. Providing Webhook Logs
| Log Field | Content |
| Event ID | Unique event reference |
| Endpoint URL | Target hook URL |
| Attempts | Each attempt with status, latency |
| Response body | First N bytes for debugging |
| Replay action | Manual replay button |
9. Implementing Webhook Deactivation
| Trigger | Action |
| N consecutive failures | Auto-disable after N (e.g. 50) |
| Email notification | Alert webhook owner |
| Manual disable | PATCH /webhooks/{id} {active:false} |
10. Testing Webhooks
| Tool | Use |
| ngrok / localtunnel | Expose local dev to public URL |
| RequestBin / Beeceptor | Inspect incoming hooks |
| Webhook test endpoint | POST /webhooks/{id}/test sends sample event |
| Stripe CLI | Forward live events to localhost |
11. Documenting Webhook Events
| Per Event | Document |
| Event type name | order.completed |
| When fired | Trigger condition |
| Payload schema | JSON Schema or example |
| Idempotency | Use event id for dedup |
| Ordering | NOT guaranteed across events |