Use Case
// Use Case

Clean your CRM, in one pass

Re-enrich every contact, validate every email, flag every job change, dedupe by email and LinkedIn URL — then write only what actually changed back to HubSpot or Salesforce. Good data stays untouched.

5,000
Contacts cleaned
2,500
Credits used
$250
Managed-mode cost
40h
Manual hours saved
the prompt — copy and pasteClaude Code
Take crm-export.csv of 5,000 HubSpot contacts, re-enrich via waterfall, validate every email with leadmagic_email_validation, flag anyone whose job title changed, and dedupe by email + LinkedIn URL. Pilot 50 rows first, then upsert changed fields back via hubspot_batch_upsert_objects.Agent setupUse prebuilt/job-change-check as the starting contract, not as the editable workflow. Create an owned Deepline scratchpad play for this use case. The .play.ts is the source of truth: iterate by editing it, rerunning it, and exporting from it rather than shipping a local post-processed CSV unless the user explicitly asks for a one-off. Start by copying the source when the prebuilt is close: deepline plays get prebuilt/job-change-check --source --out job-change-check-scratchpad.play.ts. Rename the play inside job-change-check-scratchpad.play.ts before the first run so the workflow is owned by this user/project. If the workflow needs composition, aliases, fanout, or a different provider route, start with: Create an owned .play.ts for this workflow and call prebuilt/job-change-check only as a read-only stage when it fits. Encode CSV header aliases, validation, joins, old/new columns such as old_company and new_company, status fields, miss_reason, and final export projection in the play file. Then run deepline plays check <file> and pilot 1-3 rows before scale. Keep stable step, fetch, and play-call ids for their durable boundaries. Paid provider tool calls reuse durable call receipts by play, tool, semantic input, auth scope, provider action version, and cache policy unless you intentionally change those inputs or refresh stale data.
Built-in playJob Change Detection

Why CRM data rots

B2B contact data decays measurably each year. People change jobs. Emails bounce. Companies merge or shut down. Your CRM fills up with stale records that break routing rules and waste SDR time.

The most cost-effective way to keep your CRM clean: run background agents that check job changes daily, validate emails, and flag stale records automatically.

How to clean your CRM

Step 1: Export your contacts

Pull a segment from HubSpot, Salesforce, or Attio as a CSV. Include email, name, company, and any fields you want to validate.

Step 2: Run a pilot cleanup

Tell Claude Code

Take this CSV of 5,000 HubSpot contacts. Re-enrich via waterfall. Validate every email. Flag anyone whose job title changed. Deduplicate by email + LinkedIn URL. Start with 50 as a pilot.

Claude Code reads your Deepline skills and runs:

deepline enrich --input crm-export.csv --with-waterfall email --with 'validate=leadmagic_email_validation' --rows 0:49

Step 3: Review what Deepline flags

For each contact, the output shows:

  • Email status: valid, catch-all, or bounced
  • Job change: new title and company if detected
  • Duplicate cluster: other records that match this person

Step 4: Run the full list

Tell Claude Code
Looks good. Run the full list.

Claude Code continues:

deepline enrich --input crm-export.csv --with-waterfall email --with 'validate=leadmagic_email_validation'

Step 5: Write back to CRM

Tell Claude Code
Write the cleaned data back to HubSpot.

Claude Code runs the upsert:

deepline enrich --input output.csv \
  --with '{"alias":"upsert","tool":"hubspot_batch_upsert_objects","payload":{"object_type":"contacts","id_property":"email","inputs":[{"id":"{{email}}","properties":{"email":"{{email}}","firstname":"{{first_name}}","lastname":"{{last_name}}"}}]}}'

Only changed fields update. Good data stays untouched.

What gets flagged

IssueHow Deepline detects it
Bounced emailLeadMagic or IPQualityScore validation
Job changeTitle/company mismatch vs. current LinkedIn profile
Duplicate recordSame email or LinkedIn URL across rows
Stale firmographicsCompany size, funding, or industry changed

Cost breakdown

Database sizeCreditsManaged mode cost
500 contacts250~$2.50
5,000 contacts2,500~$25
50,000 contacts25,000~$250

Compare to bundled-platform alternatives or manual spot-checks at 40+ hours per quarter.

Who uses this

  • RevOps leads responsible for data quality
  • Ops teams running quarterly hygiene before board reporting
  • Sales managers tired of reps calling people who left 6 months ago

Deploy background agents for ongoing cleanup

Instead of quarterly manual cleanups, deploy background agents that run daily:

Tell Claude Code

Deploy this as a background agent that checks job changes daily. Send me a Slack message with a summary of changes and let me approve before writing back to HubSpot.

Claude Code applies the workflow definition; cron schedule and Slack notifications are configured in the dashboard:

deepline workflows apply --payload '{"name":"crm-cleanup","trigger":{"type":"cron","schedule":"0 8 * * *"},"steps":[/* enrich + validate + writeback */]}'
# Configure recurring runs and Slack notifications via the dashboard at /workflows

Background agents research accounts across multiple providers, detect job changes, validate emails, and surface changes for your approval - all without manual exports.

Common questions

1Does this overwrite good data?+

No. Deepline only updates fields where it found newer information. If a field is blank in the enrichment, the original value stays.

2What CRMs are supported?+

HubSpot, Salesforce, and Attio have native integrations. For others, export/import via CSV.

3How do I handle duplicates?+

Deepline clusters them for review. You decide which record to keep.

CRM cleanup flow: export, enrich, validate, flag, write back