Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Handle Juicebox webhooks and events. Trigger: "juicebox webhooks", "juicebox events".
.claude/skills/jeremylongshore-juicebox-webhooks-events/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 14% | 0% |
| case-05 | ✗→✓ | ▲ Improved | -8% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-03 | ✗→✓ | ▲ Improved | -10% | 0% |
| case-07 | ✗→✓ | ▲ Improved | -3% | 0% |
Juicebox delivers webhook notifications for AI-powered people search and analysis workflows. Subscribe to events for completed analyses, updated datasets, ready exports, and quota warnings to build automated pipelines that react to Juicebox intelligence in real time without polling the API.
typescriptconst response = await fetch("https://api.juicebox.ai/v1/webhooks", { method: "POST", headers: { "Authorization": `Bearer ${process.env.JUICEBOX_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ url: "https://yourapp.com/webhooks/juicebox", events: ["analysis.completed", "dataset.updated", "export.ready", "quota.warning"], secret: process.env.JUICEBOX_WEBHOOK_SECRET, }), });
typescriptimport crypto from "crypto"; import { Request, Response, NextFunction } from "express"; function verifyJuiceboxSignature(req: Request, res: Response, next: NextFunction) { const signature = req.headers["x-juicebox-signature"] as string; const expected = crypto.createHmac("sha256", process.env.JUICEBOX_WEBHOOK_SECRET!) .update(req.body).digest("hex"); if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) { return res.status(401).json({ error: "Invalid signature" }); } next(); }
typescriptimport express from "express"; const app = express(); app.post("/webhooks/juicebox", express.raw({ type: "application/json" }), verifyJuiceboxSignature, (req, res) => { const event = JSON.parse(req.body.toString()); res.status(200).json({ received: true }); switch (event.type) { case "analysis.completed": fetchResults(event.data.analysis_id, event.data.result_count); break; case "dataset.updated": refreshDashboard(event.data.dataset_id, event.data.records_added); break; case "export.ready": downloadExport(event.data.export_id, event.data.download_url); break; case "quota.warning": notifyAdmin(event.data.usage_percent, event.data.reset_date); break; } });
| Event | Payload Fields | Use Case | |-------|---------------|----------| | analysis.completed | analysis_id, result_count, query | Fetch and process search results | | dataset.updated | dataset_id, records_added, total_records | Refresh downstream dashboards | | export.ready | export_id, download_url, format | Auto-download CSV/JSON exports | | quota.warning | usage_percent, reset_date, plan_tier | Alert admin before limit hit | | search.alert | alert_id, new_matches, criteria | Notify on new candidate matches |
typescriptconst processed = new Set<string>(); async function handleIdempotent(event: { id: string; type: string; data: any }) { if (processed.has(event.id)) return; await routeEvent(event); processed.add(event.id); if (processed.size > 10_000) { const entries = Array.from(processed); entries.slice(0, entries.length - 10_000).forEach((id) => processed.delete(id)); } }
| Issue | Cause | Fix | |-------|-------|-----| | Signature mismatch | Secret rotated without updating handler | Re-fetch secret from Juicebox dashboard | | Empty result_count | Analysis timed out | Check analysis status before processing | | Export link expired | Download URL has 1-hour TTL | Fetch immediately on export.ready event | | Quota exceeded | API calls after limit hit | Implement backoff until reset_date |
See juicebox-security-basics.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-04 | fail→pass | 13,970 | 15,003 | +7% | 1 | 1 | 0% | 2,682 | 3,052 | +14% | 0 | 0 | — |
case-05 | fail→pass | 14,104 | 3,214 | -77% | 1 | 1 | 0% | 1,588 | 1,467 | -8% | 0 | 0 | — |
case-01 | pass→pass | 20,282 | 15,412 | -24% | 1 | 1 | 0% | 3,006 | 3,184 | +6% | 0 | 0 | — |
case-02 | fail→pass | 37,167 | 18,253 | -51% | 1 | 1 | 0% | 3,045 | 3,965 | +30% | 0 | 0 | — |
case-03 | fail→pass | 11,218 | 10,042 | -10% | 1 | 1 | 0% | 2,216 | 1,984 | -10% | 0 | 0 | — |
case-06 | pass→pass | 17,785 | 8,941 | -50% | 1 | 1 | 0% | 1,943 | 1,683 | -13% | 0 | 0 | — |
case-07 | fail→pass | 17,218 | 9,023 | -48% | 1 | 1 | 0% | 1,748 | 1,689 | -3% | 0 | 0 | — |
case-08 | fail→pass | 38,252 | 16,797 | -56% | 1 | 1 | 0% | 2,714 | 3,248 | +20% | 0 | 0 | — |
case-09 | fail→fail | 24,172 | 2,792 | -88% | 1 | 1 | 0% | 1,519 | 1,502 | -1% | 0 | 0 | — |
case-10 | pass→pass | 18,414 | 11,022 | -40% | 1 | 1 | 0% | 2,264 | 2,156 | -5% | 0 | 0 | — |
case-11 | pass→pass | 14,230 | 8,337 | -41% | 1 | 1 | 0% | 1,408 | 1,609 | +14% | 0 | 0 | — |
case-12 | fail→fail | 9,355 | 2,205 | -76% | 1 | 1 | 0% | 1,589 | 1,460 | -8% | 0 | 0 | — |
case-13 | pass→fail | 5,237 | 2,464 | -53% | 1 | 1 | 0% | 939 | 1,448 | +54% | 0 | 0 | — |
case-14 | fail→pass | 20,350 | 11,632 | -43% | 1 | 1 | 0% | 2,479 | 2,834 | +14% | 0 | 0 | — |
case-15 | fail→pass | 28,814 | 3,414 | -88% | 1 | 1 | 0% | 4,104 | 1,607 | -61% | 0 | 0 | — |
case-16 | fail→pass | 13,310 | 13,981 | +5% | 1 | 1 | 0% | 2,160 | 2,761 | +28% | 0 | 0 | — |
case-17 | pass→pass | 16,390 | 7,312 | -55% | 1 | 1 | 0% | 1,819 | 1,407 | -23% | 0 | 0 | — |
case-18 | pass→pass | 15,169 | 6,841 | -55% | 1 | 1 | 0% | 1,706 | 1,290 | -24% | 0 | 0 | — |
case-19 | pass→pass | 17,145 | 16,929 | -1% | 1 | 1 | 0% | 3,458 | 3,691 | +7% | 0 | 0 | — |
case-20 | pass→pass | 18,456 | 16,436 | -11% | 1 | 1 | 0% | 2,717 | 3,279 | +21% | 0 | 0 | — |
case-21 | pass→pass | 24,715 | 18,875 | -24% | 1 | 1 | 0% | 3,292 | 4,507 | +37% | 0 | 0 | — |
case-22 | pass→pass | 13,644 | 11,161 | -18% | 1 | 1 | 0% | 2,580 | 3,245 | +26% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +36 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.