Webhook Integration Guide
This guide walks you through setting up webhook subscriptions with Hookbase to send events to your customers' endpoints.
Overview
Hookbase's outbound webhook system allows you to:
- Define event types that your application produces
- Create applications to represent your customers or tenants
- Register webhook endpoints for each application
- Subscribe endpoints to specific event types
- Send events that are automatically delivered to subscribed endpoints
Getting Started
Step 1: Create Event Types
Event types define the different kinds of events your application can produce. They follow a dot-notation naming convention.
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/event-types" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "order.created",
"displayName": "Order Created",
"description": "Triggered when a new order is placed",
"category": "orders",
"schema": "{\"type\": \"object\", \"properties\": {\"orderId\": {\"type\": \"string\"}, \"amount\": {\"type\": \"number\"}}}",
"examplePayload": "{\"orderId\": \"ord_123\", \"amount\": 99.99, \"currency\": \"USD\"}"
}'Naming conventions:
- Use lowercase letters and dots only
- Start with a noun (the entity)
- End with a past-tense verb (the action)
- Examples:
order.created,payment.succeeded,user.subscription.upgraded
Step 2: Create an Application
Applications represent your customers or tenants. Each application can have multiple endpoints.
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-applications" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corp",
"externalId": "customer_123",
"metadata": {
"plan": "enterprise",
"region": "us-east-1"
}
}'The externalId field allows you to reference applications by your own internal customer ID.
Step 3: Create Webhook Endpoints
Endpoints are the URLs where webhooks will be delivered. Each endpoint gets a unique signing secret.
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-endpoints" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"applicationId": "wh_app_xxx",
"url": "https://api.customer.com/webhooks",
"description": "Production webhook endpoint",
"timeoutSeconds": 30
}'Response:
{
"data": {
"id": "wh_ep_xxx",
"url": "https://api.customer.com/webhooks",
"secret": "whsec_abc123def456...",
"circuitState": "closed"
},
"warning": "Save the signing secret now. It will not be shown again."
}Important: Store the signing secret securely. It is only returned once at creation time.
Step 4: Create Subscriptions
Subscriptions link endpoints to event types, determining which events are delivered to each endpoint.
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-subscriptions" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"endpointId": "wh_ep_xxx",
"eventTypeId": "evt_type_xxx"
}'You can also subscribe to multiple event types at once:
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-subscriptions/bulk" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"endpointId": "wh_ep_xxx",
"eventTypeIds": ["evt_type_order_created", "evt_type_order_updated", "evt_type_order_cancelled"]
}'Step 5: Send Events
When something happens in your application, send an event to Hookbase:
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/send-event" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"eventType": "order.created",
"payload": {
"orderId": "ord_789",
"customerId": "cus_456",
"amount": 149.99,
"currency": "USD",
"items": [
{"sku": "WIDGET-001", "quantity": 2, "price": 74.99}
]
},
"idempotencyKey": "order-created-ord_789"
}'Response:
{
"data": {
"eventId": "evt_xxx",
"messagesQueued": 3,
"endpoints": [
{"id": "wh_ep_aaa", "url": "https://api.customer1.com/webhooks"},
{"id": "wh_ep_bbb", "url": "https://api.customer2.com/webhooks"},
{"id": "wh_ep_ccc", "url": "https://api.customer3.com/webhooks"}
]
}
}Event Types
Creating Event Types
Event types should be created before sending events. They provide:
- Schema validation: Define a JSON Schema to validate payloads
- Documentation: Help consumers understand event structure
- Categorization: Group related events for easier management
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/event-types" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "invoice.payment.succeeded",
"displayName": "Invoice Payment Succeeded",
"description": "Fired when an invoice payment is successfully processed",
"category": "billing",
"schema": "{\"type\": \"object\", \"required\": [\"invoiceId\", \"amount\"], \"properties\": {\"invoiceId\": {\"type\": \"string\"}, \"amount\": {\"type\": \"number\"}, \"paidAt\": {\"type\": \"string\", \"format\": \"date-time\"}}}",
"examplePayload": "{\"invoiceId\": \"inv_123\", \"amount\": 500.00, \"paidAt\": \"2024-01-15T10:30:00Z\"}",
"documentationUrl": "https://docs.example.com/webhooks/invoice-payment-succeeded"
}'Deprecating Event Types
When you need to remove an event type, deprecate it first to give consumers time to migrate:
curl -X PATCH "https://api.hookbase.app/api/organizations/{orgId}/event-types/{eventTypeId}" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"isDeprecated": true,
"deprecatedMessage": "Use invoice.paid instead. This event will be removed on 2024-06-01."
}'Label Filtering
Labels allow you to send events to specific subsets of subscribers based on metadata.
Adding Labels to Events
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/send-event" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"eventType": "order.shipped",
"payload": {"orderId": "ord_123", "carrier": "fedex"},
"labels": {
"region": "us-west",
"priority": "high",
"carrier": "fedex"
}
}'Configuring Subscription Filters
Subscriptions can filter events based on labels:
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-subscriptions" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"endpointId": "wh_ep_xxx",
"eventTypeId": "evt_type_xxx",
"labelFilters": {
"region": "us-west",
"priority": ["high", "urgent"]
},
"labelFilterMode": "all"
}'Filter modes:
all: Event must match ALL filter conditions (AND logic)any: Event must match ANY filter condition (OR logic)
Filter values:
- Single value: Exact match required
- Array of values: Event label must match any value in the array
Retry Behavior
Hookbase automatically retries failed webhook deliveries using exponential backoff.
Retry Schedule
| Attempt | Delay After Failure |
|---|---|
| 1st retry | 10 seconds |
| 2nd retry | 30 seconds |
| 3rd retry | 2 minutes |
| 4th retry | 10 minutes |
After 5 total attempts (1 initial + 4 retries), the message is moved to the Dead Letter Queue (DLQ).
What Triggers a Retry
- Network errors (timeout, connection refused, DNS failure)
- HTTP 5xx responses (server errors)
- HTTP 429 responses (rate limited)
- Request timeouts
What Does NOT Retry
- HTTP 2xx responses (success)
- HTTP 4xx responses except 429 (client errors are not retried)
Circuit Breaker
Hookbase implements a circuit breaker pattern to prevent overwhelming failing endpoints.
Circuit States
| State | Description | Behavior |
|---|---|---|
| Closed | Normal operation | All requests are sent |
| Open | Endpoint is failing | Requests are skipped, message retried later |
| Half-Open | Testing recovery | Probe requests are sent to test endpoint health |
Default Thresholds
| Parameter | Default | Description |
|---|---|---|
| Failure threshold | 5 | Consecutive failures to open circuit |
| Success threshold | 2 | Consecutive successes to close circuit |
| Cooldown period | 60 seconds | Time before testing recovery |
Configuring Circuit Breaker
Set custom thresholds when creating or updating an endpoint:
curl -X PATCH "https://api.hookbase.app/api/organizations/{orgId}/webhook-endpoints/{endpointId}" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"circuitFailureThreshold": 10,
"circuitSuccessThreshold": 3,
"circuitCooldownSeconds": 120
}'Manually Resetting Circuit Breaker
If you've fixed an endpoint issue, you can manually reset the circuit:
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-endpoints/{endpointId}/reset-circuit" \
-H "Authorization: Bearer {token}"Best Practices for Endpoint Implementation
1. Respond Quickly
Acknowledge webhooks within 5-10 seconds. Process events asynchronously if needed.
// Good: Acknowledge immediately, process async
app.post('/webhooks', async (req, res) => {
// Verify signature
verifySignature(req);
// Queue for async processing
await queue.add('processWebhook', req.body);
// Respond immediately
res.status(200).json({ received: true });
});2. Implement Idempotency
Use the x-hookbase-id header to deduplicate webhooks:
app.post('/webhooks', async (req, res) => {
const messageId = req.headers['x-hookbase-id'];
// Check if already processed
if (await redis.get(`webhook:${messageId}`)) {
return res.status(200).json({ received: true, duplicate: true });
}
// Process webhook
await processWebhook(req.body);
// Mark as processed (with TTL for cleanup)
await redis.set(`webhook:${messageId}`, '1', 'EX', 86400);
res.status(200).json({ received: true });
});3. Return Appropriate Status Codes
| Scenario | Status Code | Hookbase Behavior |
|---|---|---|
| Success | 200-299 | Mark as delivered |
| Bad request (your fault) | 400-499 (except 429) | Mark as failed, no retry |
| Rate limited | 429 | Retry with backoff |
| Server error | 500-599 | Retry with backoff |
| Timeout | - | Retry with backoff |
4. Log Webhook Receipts
Maintain an audit trail for debugging:
app.post('/webhooks', async (req, res) => {
const receipt = {
messageId: req.headers['x-hookbase-id'],
eventType: req.headers['x-hookbase-event-type'],
timestamp: req.headers['x-hookbase-timestamp'],
receivedAt: new Date().toISOString(),
payload: req.body,
};
await db.webhookReceipts.create(receipt);
// Process...
});5. Handle Signature Verification Failures Gracefully
app.post('/webhooks', (req, res) => {
try {
verifySignature(req.body, req.headers, secret);
} catch (error) {
// Log for security monitoring
console.error('Webhook signature verification failed:', {
error: error.message,
headers: req.headers,
ip: req.ip,
});
// Return 401 but don't leak details
return res.status(401).json({ error: 'Unauthorized' });
}
// Process verified webhook...
});Monitoring and Debugging
Viewing Delivery Status
List recent messages and their delivery status:
curl "https://api.hookbase.app/api/organizations/{orgId}/outbound-messages?status=failed&limit=20" \
-H "Authorization: Bearer {token}"Viewing Delivery Attempts
See all attempts for a specific message:
curl "https://api.hookbase.app/api/organizations/{orgId}/outbound-messages/{messageId}/attempts" \
-H "Authorization: Bearer {token}"Checking DLQ
View messages that have exhausted all retries:
curl "https://api.hookbase.app/api/organizations/{orgId}/outbound-messages/dlq/messages" \
-H "Authorization: Bearer {token}"Retrying Failed Messages
Replay a failed message:
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/outbound-messages/{messageId}/replay" \
-H "Authorization: Bearer {token}"Retry a DLQ message:
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/outbound-messages/dlq/{messageId}/retry" \
-H "Authorization: Bearer {token}"Next Steps
- Webhook Signature Verification - Implement signature verification in your endpoint
- Webhook API Reference - Complete API documentation
- Analytics Dashboard - Monitor delivery health and performance