← Back to list

juicebox-webhooks-events
by jeremylongshore
Hundreds of Claude Code plugins with embedded AI skills. Learn via interactive Jupyter tutorials.
⭐ 1,042🍴 135📅 Jan 23, 2026
SKILL.md
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
// First, configure in Juicebox dashboard or via API
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
// routes/webhooks.ts
import { Router } from 'express';
import crypto from 'crypto';
const router = Router();
// Verify webhook signature
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();
// Verify signature
if (!verifySignature(payload, signature, process.env.JUICEBOX_WEBHOOK_SECRET!)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(payload);
// Acknowledge receipt immediately
res.status(200).json({ received: true });
// Process event asynchronously
await processWebhookEvent(event);
});
export default router;
Step 3: Process Different Event Types
// services/webhook-processor.ts
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;
default:
console.warn(`Unknown event type: ${event.type}`);
}
}
async function handleSearchCompleted(data: { searchId: string; resultCount: number }) {
// Notify user that search is complete
await notificationService.send({
type: 'search_complete',
searchId: data.searchId,
message: `Search completed with ${data.resultCount} results`
});
}
async function handleProfileEnriched(data: { profileId: string; fields: string[] }) {
// Update local cache with enriched data
await cacheService.invalidate(`profile:${data.profileId}`);
await db.profiles.update({
where: { id: data.profileId },
data: { enrichedAt: new Date() }
});
}
async function handleExportReady(data: { exportId: string; downloadUrl: string }) {
// Notify user and store download URL
await notificationService.send({
type: 'export_ready',
exportId: data.exportId,
downloadUrl: data.downloadUrl
});
}
async function handleQuotaWarning(data: { usage: number; limit: number }) {
// Alert team about quota usage
const percentage = (data.usage / data.limit) * 100;
if (percentage > 80) {
await alertService.send({
severity: 'warning',
message: `Juicebox quota at ${percentage.toFixed(1)}%`
});
}
}
Step 4: Implement Retry Logic
// lib/webhook-queue.ts
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
}
});
}
// Worker
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.
Score
Total Score
85/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
✓人気
GitHub Stars 1000以上
+15
✓最近の活動
1ヶ月以内に更新
+10
✓フォーク
10回以上フォークされている
+5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon

