Case Study 05 · CModel Data, Inc · AI Automation

The CRM Had the Contacts. It Didn't Know Which Ones Were Worth Calling. Now It Does.

AI Pipeline · HubSpot Enrichment · ICP Scoring · RevOps

Python HubSpot Claude API Serper RevOps
3
Outputs written per record
2
Pipelines — EDO + podcast
4
Signal categories scored

The Problem

A niche buyer segment. Hundreds of records. No way to tell who was ready to move.

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

HubSpot in. Scored, enriched, rep-ready records out.

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

Four decisions that separated a pipeline that works from one that looks like it works.

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

Same architecture. Different input. Different output. One system doing two jobs.

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: a name and a website. After: everything the rep needs before the first call.

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:

Company Record — Post-Pipeline
edo_fit_score 82
edo_lane Buyer
edo_signal_note "Inland Empire EDC posted two new project manager roles and announced a $40M industrial park expansion in Q1 — active build-out signals with clear portfolio alignment. Primary buyer candidate."
Contact Record — Post-Pipeline
newsletter_hook "Given what you're building in the Inland Empire right now, I thought this might actually be worth your time —"

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

Live. Scoring real records. No manual research required on any scored company.

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