
Most CRM platforms promise intelligence but deliver spreadsheets with better branding. Lead scores get assigned manually, follow-up sequences fire based on rigid time delays, and the "AI" built into most sales tools amounts to little more than keyword matching on a contact's job title. The result: sales teams spend hours triaging leads that a genuinely intelligent system could have prioritized, tagged, and routed in seconds.
This guide walks through exactly how to connect Claude Code automation to your CRM — whether you're using HubSpot, Salesforce, Pipedrive, or a custom setup — to build a lead scoring engine that actually thinks. You'll learn how to read contact data via API, feed it to Claude, parse structured decisions back into your CRM, and trigger downstream sequences without a human in the loop.
No theoretical fluff. Just a working integration, step by step.
🚀 Want to Build This Live — With Expert Guidance?
Adventure Media is hosting a hands-on workshop where you'll master Claude Code integrations like this one in a single day. Seats are strictly limited and filling fast.
Reserve Your Spot — Limited Seats Available →Before writing a single line of code, getting the environment right prevents 80% of the debugging headaches that trip up beginners. This step covers every dependency, credential, and conceptual requirement to complete this integration successfully.
This tutorial assumes you're comfortable with basic programming concepts — variables, loops, functions, and making HTTP requests. You don't need to be a senior engineer, but if you've never written a script that calls an API, spend 30 minutes on a beginner REST API tutorial first. The concepts here build on that foundation.
Required knowledge:
.env files| Tool / Service | Purpose | Cost | Where to Get It |
|---|---|---|---|
| Anthropic API Key | Powers Claude's reasoning engine | Pay-per-token (very low cost per lead) | console.anthropic.com |
| CRM API Key | Read/write contact records | Included with CRM subscription | Your CRM's developer/settings panel |
| Python 3.9+ | Runtime environment | Free | python.org |
| anthropic Python SDK | Simplifies API calls to Claude | Free (open source) | pip install anthropic |
| python-dotenv | Manage secrets safely | Free | pip install python-dotenv |
| requests library | HTTP calls to CRM API | Free | pip install requests |
Estimated setup time for this step: 20–30 minutes.
⚠️ Security Warning: Never hardcode API keys directly in your script files. Always store them in environment variables. A hardcoded key committed to a public GitHub repo will be compromised within hours — automated bots scan for exactly this.
The examples in this guide use HubSpot's v3 Contacts API as the reference implementation, but every concept maps directly to Salesforce (REST API), Pipedrive (v1 API), or Zoho CRM. The key difference between CRMs is how they handle custom properties — the field where you'll write Claude's lead score back. Check your CRM's developer documentation to find how to create a custom numeric property or field before proceeding to Step 3.
A clean, isolated environment prevents dependency conflicts and makes the project portable. This step takes about 15 minutes and saves hours of debugging later.
Open your terminal and navigate to the folder where you want to build this project. Then run the following commands:
# Create the project folder
mkdir crm-claude-integration
cd crm-claude-integration
# Create a Python virtual environment
python3 -m venv venv
# Activate it (Mac/Linux)
source venv/bin/activate
# Activate it (Windows)
venv\Scripts\activate
# Install dependencies
pip install anthropic python-dotenv requests
Create a file named .env in your project root. This file stores your secrets locally and is never committed to version control. Add these lines, replacing the placeholder values with your actual keys:
ANTHROPIC_API_KEY=sk-ant-your-key-here
HUBSPOT_API_KEY=your-hubspot-private-app-token
CRM_BASE_URL=https://api.hubapi.com
Immediately create a .gitignore file in the same directory with this content:
.env
venv/
__pycache__/
*.pyc
Create a file named test_connection.py and run it to confirm both API connections work before building anything else:
import anthropic
import os
from dotenv import load_dotenv
load_dotenv()
client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=100,
messages=[{"role": "user", "content": "Reply with the word CONNECTED only."}]
)
print(message.content[0].text)
# Expected output: CONNECTED
If you see CONNECTED in your terminal, the Anthropic Claude Code environment is live. If you get an authentication error, double-check that your API key in the .env file has no trailing spaces and that load_dotenv() is being called before you access the key.
Common mistake to avoid: Using the wrong model name. Check Anthropic's current model documentation for the latest available model identifiers — they update periodically and an outdated string will throw an error.
The quality of Claude's lead scoring output is directly proportional to the quality of data you feed it. This step covers which CRM fields to extract, how to structure them, and how to handle missing or incomplete records — a reality in almost every live CRM.
Before writing a single API call, spend 10 minutes deciding which fields in your CRM are genuinely predictive of conversion. Most CRMs have dozens of fields — many of which are noise. The scoring model is only as good as its inputs.
Industry research on B2B sales consistently points to a core cluster of high-signal fields:
Create a file named crm_fetcher.py. This module handles all communication with your CRM API:
import requests
import os
from dotenv import load_dotenv
load_dotenv()
HUBSPOT_API_KEY = os.getenv("HUBSPOT_API_KEY")
BASE_URL = os.getenv("CRM_BASE_URL")
HEADERS = {
"Authorization": f"Bearer {HUBSPOT_API_KEY}",
"Content-Type": "application/json"
}
# Fields to pull for each contact — customize this list for your CRM
CONTACT_PROPERTIES = [
"firstname", "lastname", "email", "company",
"jobtitle", "industry", "num_employees",
"hs_analytics_num_page_views",
"hs_email_open",
"recent_deal_amount",
"days_to_close",
"hs_last_activity_date",
"num_contacted_notes",
"hs_analytics_source"
]
def fetch_unscored_contacts(limit=50):
"""
Fetches contacts that don't yet have a claude_lead_score property set.
Returns a list of contact dicts.
"""
url = f"{BASE_URL}/crm/v3/objects/contacts/search"
payload = {
"filterGroups": [
{
"filters": [
{
"propertyName": "claude_lead_score",
"operator": "NOT_HAS_PROPERTY"
}
]
}
],
"properties": CONTACT_PROPERTIES,
"limit": limit
}
response = requests.post(url, json=payload, headers=HEADERS)
response.raise_for_status()
return response.json().get("results", [])
def format_contact_for_claude(contact):
"""
Converts raw CRM contact data into a clean string summary
that Claude can reason about effectively.
"""
props = contact.get("properties", {})
return f"""
Contact ID: {contact.get('id')}
Name: {props.get('firstname', 'Unknown')} {props.get('lastname', '')}
Job Title: {props.get('jobtitle', 'Not provided')}
Company: {props.get('company', 'Not provided')}
Industry: {props.get('industry', 'Not provided')}
Company Size: {props.get('num_employees', 'Unknown')} employees
Page Views: {props.get('hs_analytics_num_page_views', 0)}
Email Opens: {props.get('hs_email_open', 0)}
Traffic Source: {props.get('hs_analytics_source', 'Unknown')}
Last Activity: {props.get('hs_last_activity_date', 'No activity recorded')}
Contact Attempts: {props.get('num_contacted_notes', 0)}
""".strip()
Pro tip: The format_contact_for_claude() function is more important than most developers realize. Claude reasons far more accurately over clean, labeled plain-text summaries than over raw JSON blobs. The natural-language format mirrors how a human sales manager would brief a colleague — and Claude responds to that framing with correspondingly human-quality judgment.
⚠️ Data Privacy Note: Before sending contact data to any external API, including Anthropic's, review your privacy policy and terms of service with your leads. For enterprise deployments, consult your legal team. Anthropic's privacy policy governs how data submitted via the API is handled.
This is the core of the entire integration — the module that takes raw contact data and returns a structured, actionable scoring decision. The key architectural insight here is that Claude should return structured JSON, not freeform text, so the output can be parsed and written back to the CRM programmatically.
Before writing the prompt, define exactly what you want Claude to return. A common mistake in early Claude Code tutorial projects is asking for unstructured output and then trying to parse it — a fragile approach that breaks on edge cases. Instead, design a strict output schema upfront:
{
"contact_id": "12345",
"score": 78,
"tier": "hot",
"primary_signals": ["pricing page visit", "VP-level title", "200+ employee company"],
"disqualifying_signals": [],
"recommended_action": "Assign to senior AE immediately. High purchase intent.",
"follow_up_sequence": "enterprise_demo_sequence",
"confidence": "high"
}
The score field is a 0–100 integer. The tier maps to a routing rule: hot (75–100), warm (40–74), cold (0–39). The follow_up_sequence is the exact identifier of a sequence in your CRM — Claude doesn't just score; it decides what to do next.
Create lead_scorer.py:
import anthropic
import json
import os
from dotenv import load_dotenv
load_dotenv()
client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
SYSTEM_PROMPT = """You are an expert B2B sales analyst scoring inbound leads for a software company.
Your ideal customer profile (ICP):
- Decision-makers (VP, Director, C-suite) at companies with 50–5000 employees
- Industries: SaaS, FinTech, E-commerce, Healthcare Tech, Professional Services
- Behavioral signals: visited pricing page, downloaded a buyer's guide, opened 3+ emails
- High urgency signals: direct demo request, multiple contacts in short timeframe
Scoring criteria:
- Job title / seniority: up to 25 points
- Company size match: up to 20 points
- Industry fit: up to 15 points
- Behavioral engagement: up to 25 points
- Recency and urgency: up to 15 points
You MUST respond with ONLY valid JSON matching this exact schema — no prose, no explanation:
{
"contact_id": "",
"score": ,
"tier": "",
"primary_signals": ["", ...],
"disqualifying_signals": ["", ...],
"recommended_action": "",
"follow_up_sequence": "",
"confidence": ""
}"""
def score_lead(contact_summary: str, contact_id: str) -> dict:
"""
Sends a formatted contact summary to Claude and returns
a structured scoring decision as a Python dict.
"""
user_message = f"""Score this lead and return the JSON scoring object.
{contact_summary}"""
try:
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=500,
system=SYSTEM_PROMPT,
messages=[{"role": "user", "content": user_message}]
)
raw_response = message.content[0].text.strip()
# Parse and validate the JSON response
scoring_result = json.loads(raw_response)
scoring_result["contact_id"] = contact_id # Ensure ID is always set
return scoring_result
except json.JSONDecodeError as e:
print(f"JSON parse error for contact {contact_id}: {e}")
print(f"Raw response was: {raw_response}")
# Return a safe default rather than crashing
return {
"contact_id": contact_id,
"score": 0,
"tier": "cold",
"primary_signals": [],
"disqualifying_signals": ["scoring_error"],
"recommended_action": "Manual review required — scoring failed",
"follow_up_sequence": "cold_outreach_sequence",
"confidence": "low"
}
Why the system prompt matters so much: The scoring rubric in the system prompt is the intellectual core of the whole system. The more precisely you define your ideal customer profile and the point weights for each dimension, the more consistent and accurate Claude's outputs will be. This is where you encode your sales team's institutional knowledge — the criteria a seasoned rep uses intuitively when triaging a new lead.
To learn Claude Code at a deeper level and customize this scoring logic for your specific industry vertical, the hands-on workshop at Adventure Media's Master Claude Code in One Day event walks through prompt engineering for structured output in detail.
Generating a score that lives only in a terminal window is useless. This step writes Claude's decision directly back into the contact record, sets the appropriate lead tier, and ensures the data is immediately visible to your sales team in the CRM dashboard.
Before writing scores back, create the custom properties to receive them. In HubSpot, navigate to Settings → Properties → Contact Properties → Create Property. Create the following:
| Property Name | Internal Name | Field Type | Purpose |
|---|---|---|---|
| Claude Lead Score | claude_lead_score |
Number | 0–100 integer score |
| Claude Lead Tier | claude_lead_tier |
Single-line text | hot / warm / cold |
| Claude Recommended Action | claude_recommended_action |
Single-line text | Plain-English next step |
| Claude Follow-Up Sequence | claude_followup_sequence |
Single-line text | Sequence identifier to trigger |
| Claude Scored At | claude_scored_at |
Date/Time | Timestamp for auditing and re-scoring logic |
Create crm_updater.py:
import requests
import os
from datetime import datetime, timezone
from dotenv import load_dotenv
load_dotenv()
HUBSPOT_API_KEY = os.getenv("HUBSPOT_API_KEY")
BASE_URL = os.getenv("CRM_BASE_URL")
HEADERS = {
"Authorization": f"Bearer {HUBSPOT_API_KEY}",
"Content-Type": "application/json"
}
def write_score_to_crm(scoring_result: dict) -> bool:
"""
Writes Claude's scoring decision back to the CRM contact record.
Returns True on success, False on failure.
"""
contact_id = scoring_result["contact_id"]
url = f"{BASE_URL}/crm/v3/objects/contacts/{contact_id}"
timestamp = datetime.now(timezone.utc).isoformat()
payload = {
"properties": {
"claude_lead_score": str(scoring_result["score"]),
"claude_lead_tier": scoring_result["tier"],
"claude_recommended_action": scoring_result["recommended_action"],
"claude_followup_sequence": scoring_result["follow_up_sequence"],
"claude_scored_at": timestamp
}
}
response = requests.patch(url, json=payload, headers=HEADERS)
if response.status_code == 200:
print(f"✅ Contact {contact_id} scored: {scoring_result['score']}/100 ({scoring_result['tier']})")
return True
else:
print(f"❌ Failed to update contact {contact_id}: {response.status_code} — {response.text}")
return False
Common mistake: HubSpot's API requires numeric values to be passed as strings in the properties object, not integers. If you pass "claude_lead_score": 78 (an integer), the API returns a 400 error. Pass "claude_lead_score": "78" (a string) instead. This is a documented quirk of the HubSpot v3 API that catches many developers off guard.
Writing a score to a CRM field is valuable. Triggering an actual follow-up workflow automatically — without any human needing to log in — is transformative. This step connects Claude's sequence recommendation to HubSpot's Sequences API, so a scored lead immediately enters the right nurture track.
There are two architectural patterns for triggering sequences based on Claude's output, each with trade-offs:
| Approach | How It Works | Pros | Cons |
|---|---|---|---|
| CRM Workflow Trigger | Claude writes a field value; a CRM workflow watches that field and fires sequences | ✅ No extra API calls ✅ Built-in CRM logging ✅ Easy to edit sequences in CRM UI | ⚠️ Requires workflow setup in CRM ⚠️ Slight delay (polling interval) |
| Direct API Enrollment | Python script calls the Sequences API directly after scoring | ✅ Immediate enrollment ✅ Full programmatic control | ⚠️ Requires Sales Hub Professional ⚠️ More complex error handling |
For most teams, the CRM Workflow Trigger approach is recommended for initial deployment. It's more resilient, easier to debug, and keeps non-technical sales operations managers in control of sequence logic without needing to modify Python code.
In HubSpot, navigate to Automation → Workflows → Create Workflow → Contact-based. Configure the trigger as:
claude_followup_sequence → is knownclaude_followup_sequenceenterprise_demo_sequence → Enroll in "Enterprise Demo Request" sequencesmb_nurture_sequence → Enroll in "SMB Educational Nurture" sequencecold_outreach_sequence → Enroll in "Cold Reactivation" sequencedisqualify → Set lifecycle stage to "Disqualified", remove from active listsThis design means your Python script only needs to write one field value, and the CRM handles all downstream routing. Adding a new sequence in the future requires only a new branch in the workflow — no code changes needed.
Individual modules that each work in isolation need an orchestration layer to run as a unified, repeatable pipeline. This step builds the main runner script and adds the logic for batch processing, rate limiting, and error recovery.
Create pipeline.py — the single script that pulls contacts, scores them, and writes results back:
import time
from crm_fetcher import fetch_unscored_contacts, format_contact_for_claude
from lead_scorer import score_lead
from crm_updater import write_score_to_crm
def run_scoring_pipeline(batch_size=20, delay_between_calls=1.0):
"""
Main pipeline: fetch → score → write → repeat
batch_size: Number of contacts to process per run
delay_between_calls: Seconds to wait between Claude API calls (rate limiting)
"""
print(f"\n🚀 Starting Claude Lead Scoring Pipeline")
print(f" Batch size: {batch_size} contacts")
print(f" Rate limit delay: {delay_between_calls}s between API calls\n")
# Step 1: Fetch unscored contacts from CRM
contacts = fetch_unscored_contacts(limit=batch_size)
if not contacts:
print("✅ No unscored contacts found. Pipeline complete.")
return
print(f"📋 Found {len(contacts)} unscored contacts to process\n")
results = {"success": 0, "failed": 0, "hot": 0, "warm": 0, "cold": 0}
for i, contact in enumerate(contacts):
contact_id = contact.get("id")
print(f"[{i+1}/{len(contacts)}] Processing contact {contact_id}...")
try:
# Step 2: Format contact data for Claude
contact_summary = format_contact_for_claude(contact)
# Step 3: Score with Claude
scoring_result = score_lead(contact_summary, contact_id)
# Step 4: Write score back to CRM
success = write_score_to_crm(scoring_result)
if success:
results["success"] += 1
results[scoring_result["tier"]] += 1
else:
results["failed"] += 1
except Exception as e:
print(f" ⚠️ Unexpected error for contact {contact_id}: {e}")
results["failed"] += 1
# Rate limiting — be a good API citizen
if i < len(contacts) - 1:
time.sleep(delay_between_calls)
# Summary report
print(f"\n{'='*50}")
print(f"Pipeline Complete — Summary:")
print(f" ✅ Successful: {results['success']}")
print(f" ❌ Failed: {results['failed']}")
print(f" 🔥 Hot leads: {results['hot']}")
print(f" 🌡️ Warm leads: {results['warm']}")
print(f" ❄️ Cold leads: {results['cold']}")
print(f"{'='*50}\n")
if __name__ == "__main__":
run_scoring_pipeline(batch_size=20, delay_between_calls=1.5)
Running the pipeline manually defeats the purpose of automation. The appropriate scheduling method depends on your infrastructure:
cron (Mac/Linux) or Windows Task Scheduler to run python pipeline.py every hourThe webhook approach delivers the fastest time-to-score — a new lead can be scored and routed within seconds of hitting your CRM. This is particularly valuable for high-intent leads like demo requests, where response time directly correlates with conversion rate according to multiple studies on B2B sales velocity.
A lead that was cold three months ago may have visited your pricing page twice this week. Static lead scores are a liability — they send fresh, high-intent contacts to the wrong sequence because their score reflects who they were, not who they are now. This step adds a re-scoring layer that identifies contacts whose behavior has changed significantly since their last score.
Not every contact needs re-scoring on every pipeline run. Indiscriminate re-scoring wastes API tokens and creates noise in your CRM history. The following framework — developed through patterns observed across high-volume sales automation deployments — identifies which contacts genuinely warrant a fresh look:
| Trigger Event | Re-Score Priority | Expected Score Change |
|---|---|---|
| Pricing page visit (first time) | 🔥 Immediate | +15 to +25 points typical |
| Demo request form submission | 🔥 Immediate | Often pushes to "hot" tier |
| 3+ email opens in 7 days | ⚡ High | +10 to +20 points typical |
| Job title change (promotion to VP+) | ⚡ High | Significant seniority boost |
| 90+ days of zero activity | 📉 Decay re-score | -10 to -20 points typical |
| Company acquired or merged | ⚠️ Review | Variable — may disqualify or upgrade |
Implement this by adding a secondary CRM query to crm_fetcher.py that fetches contacts where hs_last_activity_date is within the last 48 hours AND claude_scored_at is more than 7 days ago. These are your re-score candidates — contacts whose recent behavior outpaces their existing score.
This is also where the power of AI coding assistant workflows becomes truly apparent: a traditional rules-based scoring system would require you to hardcode every re-scoring condition. Claude can reason about the relative importance of combined signals — for instance, a cold lead who visited the pricing page AND opened three emails in the same day is almost certainly more valuable than those signals in isolation suggest.
🎯 Go From Tutorial to Production in One Day
Adventure Media's Master Claude Code in One Day workshop takes you through live builds like this one — with real CRM data, real API calls, and expert instructors on hand. This is the fastest path from reading about Claude Code to actually deploying it. Don't miss this — seats are filling fast.
Register Now — Spots Filling Fast →Any automated system that writes data into a CRM and triggers sales sequences carries real operational risk if left unmonitored. A misfire — scoring a hot lead as cold, or enrolling a VIP prospect in a cold outreach sequence — can damage real relationships. This step builds a lightweight monitoring layer and an audit trail that keeps the system accountable.
Add logging to pipeline.py to write every scoring decision to a local CSV file. This creates an audit trail you can review weekly and use to improve the scoring prompt over time:
import csv
from datetime import datetime
def log_scoring_decision(scoring_result: dict, log_file="scoring_log.csv"):
"""Appends a scoring decision to the audit log."""
fieldnames = [
"timestamp", "contact_id", "score", "tier",
"confidence", "follow_up_sequence", "primary_signals"
]
row = {
"timestamp": datetime.now().isoformat(),
"contact_id": scoring_result["contact_id"],
"score": scoring_result["score"],
"tier": scoring_result["tier"],
"confidence": scoring_result["confidence"],
"follow_up_sequence": scoring_result["follow_up_sequence"],
"primary_signals": "|".join(scoring_result.get("primary_signals", []))
}
# Write header only if file doesn't exist
import os
write_header = not os.path.exists(log_file)
with open(log_file, "a", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
if write_header:
writer.writeheader()
writer.writerow(row)
Schedule 30 minutes each week to review the scoring log against actual sales outcomes. The key calibration questions:
Over time, this review loop — where human sales judgment calibrates the AI's criteria — creates a continuously improving system. The system prompt in lead_scorer.py is a living document that should be refined monthly based on outcome data. This is the core practice of responsible claude code automation at scale.
The cost per lead scored is extremely low. A typical contact summary is roughly 200–300 tokens, and Claude's response is another 100–200 tokens. At current API pricing for Claude models, scoring 1,000 leads costs well under $5. Even at 10,000 leads per month, the API cost is negligible compared to the sales team hours saved.
Any CRM with a REST API works — which includes HubSpot, Salesforce, Pipedrive, Zoho CRM, Close, Copper, and dozens of others. The Python modules in this guide use HubSpot as the reference, but the architecture (fetch → score → write back) is CRM-agnostic. Only the API endpoints and authentication headers change.
This is a legal question that requires professional advice for your specific situation. Generally speaking, using contact data stored in your CRM for internal scoring purposes falls within legitimate interest under most privacy frameworks — but you should review your privacy policy, ensure your consent language covers AI-assisted processing, and consult legal counsel for any enterprise deployment. Anthropic's API terms specify that data submitted via the API is not used to train their models by default.
The score_lead() function includes a try/except block around the JSON parse step. If parsing fails, the function returns a safe default object that scores the contact as cold and flags it for manual review. This prevents a single malformed response from crashing the entire pipeline. In practice, Claude returns well-formed JSON reliably when the system prompt is explicit about the schema — malformed responses are rare with a well-constructed prompt.
Yes. The architecture is model-agnostic. The score_lead() function can be adapted to use OpenAI's API, Google's Gemini, or any model with a chat completion API. That said, Claude demonstrates particularly strong performance on structured-output tasks and following precise JSON schemas — which is why it's the recommended choice for this use case among many practitioners who have tested multiple models side-by-side.
The pipeline includes a configurable delay_between_calls parameter (default: 1.5 seconds). For most use cases, this keeps you well within rate limits. For high-volume processing, implement exponential backoff: catch anthropic.RateLimitError and retry with increasing delays (2s, 4s, 8s, up to a maximum). Anthropic's rate limit documentation details the current limits by tier.
Missing fields are normal — handle them gracefully in format_contact_for_claude() with .get("field_name", "Not available") and pass the "Not available" string to Claude. Claude is trained to express lower confidence when key data points are absent, and the confidence field in the output schema captures this. A "low confidence" score should trigger a data enrichment step (via tools like Clearbit or Apollo) before the score is acted upon.
Create a test set of 20–30 contacts whose eventual outcome you already know (converted customers, disqualified leads, long-term nurture contacts). Run them through the pipeline and compare Claude's scores against the actual outcomes. Adjust the ICP criteria in the system prompt until the test set produces scores that align with known outcomes. Only after validating on historical data should the pipeline run against live, active prospects.
Absolutely. The system prompt in lead_scorer.py is the scoring model — you can create multiple versions of this file with different ICPs, scoring weights, and sequence identifiers. Add a product line or segment field to your CRM, read it in crm_fetcher.py, and route contacts to the appropriate scoring function based on that value. This creates a multi-model scoring architecture that serves different business units from one pipeline.
The examples are optimized for B2B SaaS, but the architecture applies equally to B2C and e-commerce. For e-commerce, replace firmographic signals (company size, industry) with behavioral signals (cart abandonment, product category views, purchase history, average order value). The system prompt's ICP definition is the only thing that needs to change — the Python code is identical.
The fastest path is a structured, hands-on environment where you build real integrations with live feedback. Reading documentation covers the theory; actually debugging a pipeline that's calling two APIs simultaneously is where the learning happens. Adventure Media's Master Claude Code in One Day workshop is specifically designed for this — you leave with working code, not just notes.
Claude Code refers specifically to Anthropic's agentic coding tool that can read, write, and execute code in your local environment directly. The API integration in this guide uses Claude's intelligence within a Python script you write — Claude is the reasoning engine, but your code orchestrates the workflow. Both are valid approaches; the API approach gives you more control over data flow and is more appropriate for production CRM integrations where you need deterministic error handling.
Join our Claude Code events
Learn more →
We'll get back to you within a day to schedule a quick strategy call. We can also communicate over email if that's easier for you.
New York
1074 Broadway
Woodmere, NY
Philadelphia
1429 Walnut Street
Philadelphia, PA
Florida
433 Plaza Real
Boca Raton, FL
info@adventureppc.com
(516) 218-3722
Over 300,000 marketers from around the world have leveled up their skillset with AdVenture premium and free resources. Whether you're a CMO or a new student of digital marketing, there's something here for you.
Named one of the most important advertising books of all time.
buy on amazon


Over ten hours of lectures and workshops from our DOLAH Conference, themed: "Marketing Solutions for the AI Revolution"
check out dolah
Resources, guides, and courses for digital marketers, CMOs, and students. Brought to you by the agency chosen by Google to train Google's top Premier Partner Agencies.
Over 100 hours of video training and 60+ downloadable resources
view bundles →