| name | juicebox-webhooks-events |
| description | Implement Juicebox webhook handling.
Use when setting up event notifications, processing webhooks,
or integrating real-time updates from Juicebox.
Trigger with phrases like "juicebox webhooks", "juicebox events",
"juicebox notifications", "juicebox real-time".
|
| allowed-tools | Read, Write, Edit, Bash(gh:*), Bash(curl:*) |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Juicebox Webhooks & Events
Overview
Implement webhook handlers for real-time Juicebox events and notifications.
Prerequisites
- Juicebox account with webhooks enabled
- HTTPS endpoint for webhook delivery
- Request signature verification capability
Instructions
Step 1: Register Webhook Endpoint
import { JuiceboxClient } from '@juicebox/sdk';
const client = new JuiceboxClient({
apiKey: process.env.JUICEBOX_API_KEY!
});
await client.webhooks.create({
url: 'https://your-app.com/webhooks/juicebox',
events: [
'search.completed',
'profile.enriched',
'export.ready',
'quota.warning'
],
secret: process.env.JUICEBOX_WEBHOOK_SECRET
});
Step 2: Implement Webhook Handler
import { Router } from 'express';
import crypto from 'crypto';
const router = Router();
function verifySignature(payload: string, signature: string, secret: string): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expected}`)
);
}
router.post('/webhooks/juicebox', express.raw({ type: 'application/json' }), async (req, res) => {
const signature = req.headers['x-juicebox-signature'] as string;
const payload = req.body.toString();
if (!(payload, signature, process..!)) {
res.().({ : });
}
event = .(payload);
res.().({ : });
(event);
});
router;
Step 3: Process Different Event Types
interface WebhookEvent {
id: string;
type: string;
timestamp: string;
data: any;
}
export async function processWebhookEvent(event: WebhookEvent): Promise<void> {
console.log(`Processing event: ${event.type} (${event.id})`);
switch (event.type) {
case 'search.completed':
await handleSearchCompleted(event.data);
break;
case 'profile.enriched':
await handleProfileEnriched(event.data);
break;
case 'export.ready':
await handleExportReady(event.data);
break;
case 'quota.warning':
await handleQuotaWarning(event.data);
break;
:
.();
}
}
() {
notificationService.({
: ,
: data.,
:
});
}
() {
cacheService.();
db..({
: { : data. },
: { : () }
});
}
() {
notificationService.({
: ,
: data.,
: data.
});
}
() {
percentage = (data. / data.) * ;
(percentage > ) {
alertService.({
: ,
:
});
}
}
Step 4: Implement Retry Logic
import { Queue } from 'bullmq';
const webhookQueue = new Queue('juicebox-webhooks', {
connection: { host: 'localhost', port: 6379 }
});
export async function queueWebhookProcessing(event: WebhookEvent): Promise<void> {
await webhookQueue.add('process', event, {
attempts: 3,
backoff: {
type: 'exponential',
delay: 1000
}
});
}
import { Worker } from 'bullmq';
new Worker('juicebox-webhooks', async (job) => {
await processWebhookEvent(job.data);
}, {
connection: { host: 'localhost', port: 6379 }
});
Webhook Events Reference
| Event | Description | Payload |
|---|
search.completed | Async search finished | searchId, resultCount |
profile.enriched | Profile data enriched | profileId, fields |
export.ready | Bulk export ready | exportId, downloadUrl |
quota.warning | Approaching quota limit | usage, limit |
key.rotated | API key rotated | newKeyPrefix |
Output
- Webhook endpoint handler
- Signature verification
- Event type processors
- Retry queue with backoff
Error Handling
| Issue | Cause | Solution |
|---|
| Invalid signature | Wrong secret | Verify webhook secret |
| Duplicate events | Network retry | Implement idempotency |
| Processing timeout | Slow handler | Use async queue |
Resources
Next Steps
After webhooks, see juicebox-performance-tuning for optimization.