Case Study 05 · CModel Data, Inc · AI Automation
The Problem
EDOs — Economic Development Organizations — are a high-value, hard-to-reach buyer. CModel had hundreds of them in HubSpot. What they didn't have was intelligence. No signal layer. No way to distinguish organizations actively expanding from ones that were dormant. No way to know which ones had live RFPs, hiring cycles that signaled a build-out, or recent grant activity that created a budget to spend.
Every record looked the same from inside the CRM. Reps had names, org types, and a contact field. The research process was manual — open the record, search the org by name, read through results, decide if there was a signal worth acting on. Multiply that across hundreds of records and the math doesn't work. You either research at scale and don't sell, or you sell and fly blind.
The System
The pipeline runs end to end from a HubSpot CRM list. Each company in the EDO Master List flows through three stages.
First, Serper pulls live web signals for the organization — five search results per company covering hiring activity, expansion announcements, grant funding, public RFPs, and revitalization projects. The search is broad by design: organic web search, not a news feed, because the signal that matters for EDO scoring is often months old rather than breaking.
Then Claude scores each organization against a four-category ICP rubric: portfolio fit, buyer potential, timing signals, and reachability. Each category contributes a weighted sub-score. The total lands between 0 and 100. Claude also assigns a lane — Buyer, Channel, or Both — based on how the org fits CModel's go-to-market structure.
Finally, the results write back to HubSpot automatically. Three fields update on the company record: the score, the lane, and a two-sentence signal note written for a rep to read before a call. A fourth field — a personalized newsletter hook — writes to the primary contact. No manual entry. No copy-paste. The rep opens the record and the work is already done.
Technical Decisions
Serper has two endpoints that seem interchangeable: /search and /news. News results are recent by definition — useful for rapidly changing topics, not useful for EDOs, where the most relevant signal (a revitalization project, a major employer announcement, a grant win) might be six months old. Organic search returns that context. News doesn't. Switched early and the scoring quality improved immediately.
HubSpot's auth model has a gotcha. The platform is actively deprecating Personal Access Tokens in favor of Private App tokens. The difference isn't just syntactic — Private Apps require explicit permission scoping. The CRM Lists API requires crm.lists.read scoped separately from standard CRM read access. Standard access doesn't include it. The list membership endpoint returned nothing until that scope was added explicitly.
Claude occasionally wraps JSON output in markdown code fences even when instructed not to. Without a fallback, json.loads() fails on those responses and the pipeline dies silently on those records. Built a .replace() strip before every parse call. One edge case that looks minor and breaks roughly one in ten responses without it.
The HubSpot associations endpoint is separate from the companies endpoint. Writing the newsletter hook to the contact requires resolving the company-to-contact association first, then making a second write call to the contact record. One API call became four. Sequencing those correctly was what made the full record enrichment possible.
The Second Pipeline
The EDO scoring pipeline wasn't the end of the architecture — it was the foundation for a second one.
CModel runs a podcast. Potential guests reach out or get identified. The qualification process was manual: someone had to research the guest, decide if they were a fit, and log it somewhere in HubSpot. The pipeline now handles it. A Riverside transcript or intake submission comes in, Claude extracts a guest profile from the content, Serper enriches it with current web information, Claude scores fit against the podcast's audience criteria, and podcast_fit_status gets written to the contact record in HubSpot.
Same API integrations. Same orchestration pattern. Different rubric, different input source, different output field. Building the EDO pipeline correctly meant the podcast pipeline cost a fraction of the original build time.
What a Scored Record Looks Like
Before the pipeline runs, an EDO record in HubSpot looks like every other company in the CRM — org name, type, website, a contact or two. No intelligence. The rep has to guess whether it's worth their time.
After:
The rep opens the record knowing exactly who they're calling, why, what's happening in the org right now, and how to open the conversation. None of that existed in the CRM before.
"The job wasn't to automate research. It was to replace the research step entirely — so the rep opens a record already knowing what to say."
Current Status
The pipeline is in production. It's scoring real EDO records today. Runs trigger manually for batch processing of the full list and via webhook when new companies are added. Every scored record in HubSpot has a fit score, a lane, a signal note, and a personalized hook on the contact. Manual research on any of those records has been replaced entirely.
The podcast intake pipeline runs alongside it — same system, separate trigger, separate output field. Both are live. Both are writing to HubSpot on every run.
What Was Built