smithery/jeremylongshore

juicebox-webhooks-events

Handle Juicebox webhooks and events. '

Installation

$ npx skills add smithery/jeremylongshore --skill juicebox-webhooks-events

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/jeremylongshore · top by installs.

npx skills add smithery/jeremylongshore

Browse all from smithery/jeremylongshore

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.16.0
LicenseMIT
CompatibilityDesigned for Claude Code
Allowed toolsRead, Write, Edit, Grep
Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,232 B
  • docs SUMMARY.md 296 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Juicebox Webhooks & Events

Overview

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.

Webhook Registration

const 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,
  }),
});

Signature Verification

import 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();
}

Event Handler

import 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 Types

Event Payload Fields Use Case
analysis.completed analysisid, resultcount, query Fetch and process search results
dataset.updated datasetid, recordsadded, total_records Refresh downstream dashboards
export.ready exportid, downloadurl, format Auto-download CSV/JSON exports
quota.warning usagepercent, resetdate, plan_tier Alert admin before limit hit
search.alert alertid, newmatches, criteria Notify on new candidate matches

Retry & Idempotency

const 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));
  }
}

Error Handling

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

Prerequisites

  • A secret-manager webhook secret, event-origin allowlist, replay-window policy, source-authority check, suppression policy, and opaque event ledger.

Instructions

  1. Authenticate origin before parsing, validate timestamp/event ID, and reject unknown sources, stale deliveries, and malformed payloads.
  2. Store only a bounded redacted envelope and use event ID plus target revision as the idempotency key.
  3. Verify source authority, suppression, and destination before enqueueing enrichment; quarantine uncertainty instead of exporting or enriching a contact.
  4. Canary one sandbox source, observe aggregate policy probes, then promote or disable the consumer.
  5. Route exhausted retries to reviewed recovery without replaying non-idempotent writes.

Output

Return an event receipt with type, opaque ID, signature/timestamp result, source/destination, suppression result, idempotency outcome, export-count assertion, queue state, and rollback reference. Exclude payload contact data and signatures.

Examples

type=prospect.updated; event=evt-opaque-9; signature=pass; replay=absent; source=synthetic; suppression=pass; contacts_exported=0; rollback=consumer-disabled proves the event boundary.

Resources

  • Juicebox API Docs

Next Steps

See juicebox-security-basics.