Getting Started
This guide walks you through integrating Hookbase into your application to provide webhooks to your customers.
Overview
Hookbase provides two main packages for integration:
- @hookbase/sdk - Server-side SDK for sending webhooks and managing resources
- @hookbase/portal - Embeddable React components for customer-facing webhook management
Architecture
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Your App │────▶│ Hookbase │────▶│ Customer's │
│ (Backend) │ │ API │ │ Endpoint │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Your App │ │ Hookbase │
│ (Frontend) │────▶│ Portal │
└─────────────────┘ └─────────────────┘Quick Start
1. Install the SDK
bash
npm install @hookbase/sdk2. Initialize the Client
typescript
import { Hookbase } from '@hookbase/sdk';
const hookbase = new Hookbase({
apiKey: process.env.HOOKBASE_API_KEY,
});3. Create an Application for Your Customer
typescript
// When a new customer signs up
const app = await hookbase.applications.create({
name: customer.name,
uid: customer.id, // Your internal customer ID
metadata: {
plan: customer.plan,
email: customer.email,
},
});4. Define Event Types
typescript
// Set up the event types your customers can subscribe to
await hookbase.eventTypes.create({
name: 'order.created',
displayName: 'Order Created',
description: 'Triggered when a new order is placed',
category: 'Orders',
});
await hookbase.eventTypes.create({
name: 'order.shipped',
displayName: 'Order Shipped',
description: 'Triggered when an order ships',
category: 'Orders',
});
await hookbase.eventTypes.create({
name: 'payment.completed',
displayName: 'Payment Completed',
description: 'Triggered when payment is received',
category: 'Payments',
});5. Send Webhooks
typescript
// When an event occurs in your application
await hookbase.messages.send(customer.hookbaseAppId, {
eventType: 'order.created',
payload: {
orderId: order.id,
amount: order.total,
currency: order.currency,
items: order.items,
customer: {
id: order.customerId,
email: order.customerEmail,
},
},
eventId: `order_created_${order.id}`, // For deduplication
});Embed the Portal
1. Install the Portal Package
bash
npm install @hookbase/portal2. Generate a Portal Token
typescript
// Backend API endpoint
app.get('/api/webhook-portal-token', async (req, res) => {
const customer = await getCustomerFromSession(req);
const token = await hookbase.portalTokens.create(customer.hookbaseAppId, {
expiresIn: 3600, // 1 hour
});
res.json({ token: token.token });
});3. Embed the Portal
tsx
import { useState, useEffect } from 'react';
import {
HookbasePortal,
EndpointList,
EndpointForm,
SubscriptionManager,
MessageLog,
} from '@hookbase/portal';
import '@hookbase/portal/styles.css';
function WebhookSettings() {
const [portalToken, setPortalToken] = useState<string | null>(null);
const [selectedEndpoint, setSelectedEndpoint] = useState(null);
useEffect(() => {
fetch('/api/webhook-portal-token')
.then((res) => res.json())
.then((data) => setPortalToken(data.token));
}, []);
if (!portalToken) return <div>Loading...</div>;
return (
<HookbasePortal token={portalToken}>
<div className="grid grid-cols-2 gap-6">
<div>
<h2 className="text-xl font-semibold mb-4">Endpoints</h2>
<EndpointForm
onSuccess={(endpoint, secret) => {
// Show the secret to the user - it won't be available again
alert(`Save this secret: ${secret}`);
}}
/>
<EndpointList
onEndpointClick={setSelectedEndpoint}
/>
</div>
<div>
{selectedEndpoint ? (
<>
<h2 className="text-xl font-semibold mb-4">Subscriptions</h2>
<SubscriptionManager endpointId={selectedEndpoint.id} />
</>
) : (
<p>Select an endpoint to manage subscriptions</p>
)}
</div>
</div>
<div className="mt-8">
<h2 className="text-xl font-semibold mb-4">Delivery History</h2>
<MessageLog
limit={25}
refreshInterval={30000}
/>
</div>
</HookbasePortal>
);
}Verify Incoming Webhooks
When your customers receive webhooks, they need to verify the signature.
Share This Code with Your Customers
typescript
import { createWebhook } from '@hookbase/sdk';
// Create a verifier with the endpoint's signing secret
const webhook = createWebhook(process.env.WEBHOOK_SECRET);
// Express.js example
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
try {
const payload = webhook.verify(req.body.toString(), req.headers);
// Process the webhook
switch (payload.type) {
case 'order.created':
handleOrderCreated(payload.data);
break;
case 'payment.completed':
handlePaymentCompleted(payload.data);
break;
}
res.status(200).send('OK');
} catch (error) {
console.error('Webhook verification failed:', error);
res.status(401).send('Invalid signature');
}
});Best Practices
1. Use Idempotency Keys
Always include an eventId when sending webhooks to prevent duplicate deliveries:
typescript
await hookbase.messages.send(appId, {
eventType: 'order.created',
payload: orderData,
eventId: `order_created_${order.id}`,
});2. Use Application UIDs
Map your internal customer IDs to Hookbase applications:
typescript
// Store the Hookbase app ID in your database
const app = await hookbase.applications.getOrCreate(customer.id, {
name: customer.name,
});
// Later, use the UID to find the app
const app = await hookbase.applications.getByUid(customer.id);3. Handle Delivery Failures
Monitor failed deliveries and alert your customers:
typescript
// List failed messages
const { data: failures } = await hookbase.messages.listAllOutbound(appId, {
status: 'exhausted',
});
// Notify customer about failures
for (const failure of failures) {
await notifyCustomer(appId, {
message: `Webhook delivery failed to ${failure.endpointUrl}`,
eventType: failure.eventType,
error: failure.lastError,
});
}4. Implement Retry Logic
When your customers' endpoints fail, Hookbase automatically retries with exponential backoff. You can also manually retry:
typescript
// Retry a specific failed delivery
await hookbase.messages.retry(appId, outboundMessageId);
// Resend to all endpoints
await hookbase.messages.resend(appId, messageId);5. Use Event Categories
Organize your event types into categories for better UX:
typescript
await hookbase.eventTypes.create({
name: 'order.created',
category: 'Orders',
});
await hookbase.eventTypes.create({
name: 'order.shipped',
category: 'Orders',
});
await hookbase.eventTypes.create({
name: 'invoice.created',
category: 'Billing',
});Webhook Payload Format
Webhooks are delivered with the following structure:
json
{
"type": "order.created",
"data": {
"orderId": "ord_123",
"amount": 99.99,
"currency": "USD"
},
"timestamp": "2024-01-15T10:30:00Z",
"webhookId": "msg_abc123"
}Headers
| Header | Description |
|---|---|
webhook-id | Unique identifier for this delivery attempt |
webhook-timestamp | Unix timestamp when the webhook was sent |
webhook-signature | HMAC-SHA256 signature for verification |
Content-Type | application/json |
Rate Limits
| Resource | Limit |
|---|---|
| API Requests | 1000/minute |
| Webhook Sends | 10000/minute |
| Portal Tokens | 100/hour per application |
Rate limit headers are included in all API responses:
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset
Support
- Documentation: https://hookbase.app/docs
- API Reference: https://hookbase.app/docs/api
- GitHub: https://github.com/hookbase/hookbase
- Email: [email protected]