ClaudeLoops
/
Inbound lead → enriched CRM row
All loops
SalesMedium 12 min· claude-sonnet-4-5

Inbound lead → enriched CRM row

HMAC-verified webhook → Claude enrichment → HubSpot upsert with score.

NOT DEPLOYEDNOT DEPLOYED
0185ms
Trigger
POST https://hooks.claudeloops.run/lead-webhook-enrich-crm · event=github.push:main
021265ms
Agent
claude-sonnet-4-5 · in 1165 tok · out 588 tok
03295ms
Tools
fetch-mcp/anthropic:messages.create → 200 OK · 225ms
0475ms
Verify
schema check · pydantic v2 passed
05165ms
Output
hubspot contact scored · 87/100
0645ms
Notify
audit log written · runbook link attached
SUCCESS
0%
0 runs
P50
0ms
median
P95
0ms
tail
AVG COST
per run
LAST OK
never
LAST FAIL
never
none
Latency · last 30 runs0 samples
no runs yet
Latest output · what your users see
Draft email
From: loop@claudeloops.run
To: priya@northwind.io
Re: pilot for RAG pipelines

Thanks for the note — sharing a 2-min Loom that shows the exact locker rotation flow you asked about, plus a 14-day trial link scoped to your workspace only.

// press Test to run once · Watch live to keep streaming · Deploy to make it real
The problem

Raw form submissions arrive without company size, industry, or fit score — your AEs waste the first ten minutes researching every lead by hand.

The outcome

Every lead lands in HubSpot already enriched (industry, headcount, ICP fit 0–100). AEs work the queue top-down.

Ingredients & skills

Secrets
  • ANTHROPIC_API_KEY
  • HUBSPOT_TOKEN
  • LEAD_WEBHOOK_SECRET
Providers
  • Anthropic
  • HubSpot
MCP servers
  • fetch-mcp
#sales#webhook#hubspot

How it works

A public `/api/public/lead` endpoint receives marketing-form posts, verifies the HMAC signature, asks Claude to enrich and score the lead, and upserts into HubSpot.

Step 1

1 — Expose the public route

Anything under `/api/public/*` skips auth on the published site — perfect for inbound webhooks. Always verify before processing.

src/routes/api/public/lead.ts
import { createFileRoute } from "@tanstack/react-router";
import { createHmac, timingSafeEqual } from "node:crypto";

export const Route = createFileRoute("/api/public/lead")({
  server: { handlers: { POST: async ({ request }) => {
    const sig = request.headers.get("x-signature") ?? "";
    const body = await request.text();
    const expected = createHmac("sha256", process.env.LEAD_WEBHOOK_SECRET!).update(body).digest("hex");
    if (!timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return new Response("bad sig", { status: 401 });
    const lead = JSON.parse(body);
    const enriched = await enrich(lead);
    await upsertHubspot(enriched);
    return new Response("ok");
  } } },
});
Step 2

2 — Enrichment prompt

Claude returns strict JSON. We force the schema via a tool definition.

enrich.ts
export async function enrich(lead: { email: string; company?: string }) {
  const r = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: { "x-api-key": process.env.ANTHROPIC_API_KEY!, "anthropic-version": "2023-06-01", "content-type": "application/json" },
    body: JSON.stringify({
      model: "claude-sonnet-4-5",
      max_tokens: 400,
      tools: [{ name: "enriched", input_schema: { type: "object", properties: { industry: { type: "string" }, headcount: { type: "integer" }, icp_fit: { type: "integer", minimum: 0, maximum: 100 } }, required: ["industry", "headcount", "icp_fit"] } }],
      tool_choice: { type: "tool", name: "enriched" },
      messages: [{ role: "user", content: `Enrich this lead: ${JSON.stringify(lead)}` }],
    }),
  }).then((r) => r.json());
  return { ...lead, ...r.content[0].input };
}
Step 3

3 — Upsert into HubSpot

Idempotent on email. ICP fit becomes a custom property.

typescript
async function upsertHubspot(lead: any) {
  await fetch("https://api.hubapi.com/crm/v3/objects/contacts/" + encodeURIComponent(lead.email) + "?idProperty=email", {
    method: "PATCH",
    headers: { Authorization: `Bearer ${process.env.HUBSPOT_TOKEN}`, "content-type": "application/json" },
    body: JSON.stringify({ properties: { email: lead.email, industry: lead.industry, headcount: lead.headcount, icp_fit: lead.icp_fit } }),
  });
}
One-line deploy

The button above runs the same command with your saved config. This is the raw CLI form.

bash
npx claudeloops deploy lead-enricher
https://hooks.claudeloops.run/lead-webhook-enrich-crm

Related loops