AgentStack
SKILL verified MIT Self-run

Upload Leads

skill-mattsezgin-unofficial-smartlead-cli-upload-leads · by MattSezgin

Upload leads from a CSV file to a Smartlead campaign with automatic deduplication, 100-per-batch pagination, and lead-validation. Reports added vs skipped vs failed counts. Use when the user wants to upload, import, add, or push leads to a campaign — from a CSV, JSON, or any structured lead list.

No reviews yet
0 installs
10 views
0.0% view→install

Install

$ agentstack add skill-mattsezgin-unofficial-smartlead-cli-upload-leads

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Upload Leads? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

> Before running: verify exact flag names with smartlead --help. Flag shapes shown below are illustrative — confirm against the actual CLI.

/upload-leads

You're loading a lead list into a Smartlead campaign.

What you need from the user

  • Campaign ID to upload to
  • Lead source — CSV path, JSON file, or pasted list
  • Dedup scope — just this campaign, or check against all campaigns?

Step 1 — Validate the source

Look at the file first. Confirm columns:

  • email (required)
  • first_name, last_name (recommended)
  • company_name (recommended)
  • linkedin_url, phone_number, website (optional)
  • Anything else → goes into custom_fields for personalization
head -5 
wc -l 

Report row count, column names, and a sample row. Confirm with user before uploading.

Step 2 — Pre-validation

Filter obviously bad emails

# Emails missing @, or with invalid TLD
grep -E '^[^@]+@[^@]+\.[a-z]{2,}$' leads.csv > leads-cleaned.csv

Flag count of dropped rows.

Optional: ZeroBounce / NeverBounce validation

If the user has 1000+ leads and bounces matter, recommend pre-validating with an external service before upload. Smartlead doesn't validate emails at upload time.

Step 3 — Dedupe

Against this campaign

smartlead leads list  --output json | jq -r '.[].email' > existing.txt

Then filter the upload CSV:

awk -F, 'NR==FNR{a[$1]; next} !($1 in a)' existing.txt leads.csv > new-leads.csv

Against all live campaigns (broader dedup)

Important for B2B — you don't want the same prospect getting hit by Campaign A AND Campaign B.

# Pull emails from all active campaigns
smartlead campaigns list --output json | jq -r '.[] | select(.status == "ACTIVE") | .id' | \
  while read cid; do
    smartlead leads list $cid --output json | jq -r '.[].email'
  done | sort -u > all-active.txt

# Filter
awk -F, 'NR==FNR{a[$1]; next} !($1 in a)' all-active.txt leads.csv > new-leads.csv

Report: started with X leads, after dedup Y remain (Z dropped).

Step 4 — Batch upload (Smartlead caps at 100 per request)

The CLI handles pagination, but if you're hitting the API directly:

smartlead leads add  --csv new-leads.csv

The command splits into 100-row batches automatically and reports per-batch results.

For very large files (10K+), recommend uploading in chunks of 5K with a sleep between, to stay well under rate limits (see docs/learnings/rate-limits.md).

Step 5 — Verify upload

smartlead leads list  --output json | jq 'length'

Should match expected count. If short, look at the upload command's error log — Smartlead silently rejects rows with malformed custom_fields.

Step 6 — Report

Summarize for the user:

✓ Uploaded X new leads to campaign 
✓ Skipped Y duplicates (already in this or other campaigns)
✓ Dropped Z invalid rows (bad email format / missing required fields)
Campaign now has N total leads.

Important gotcha — leads are shared across campaigns

Smartlead's data model is: email = unique lead at the account level, NOT per-campaign. If you upload the same email to Campaign A then to Campaign B:

  • Both campaigns reference the SAME lead record
  • custom_fields set on Campaign A propagate to Campaign B's view of that lead
  • You CAN'T have per-campaign custom_fields for the same email

Practical implication: if you're A/B testing personalization fields, use DIFFERENT emails (or different campaigns with different lead pools), not the same lead in two campaigns.

(More: docs/learnings/campaign-cloning-runbook.md)

Reference

  • docs/learnings/campaign-cloning-runbook.md — lead-sharing behavior
  • docs/learnings/rate-limits.md — pagination and throttling

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.