contactctl Try ContactCTL

Every contact job, one command each

ContactCTL packs finding, verifying, enriching, and discovering B2B contacts into a CLI an agent can run end to end. Here is the full inventory.

agent — ~/work
$ ctc whois jane@acme.com
Jane Smith — VP Growth, Acme (acme.com)
# charged: 1 credit
 
$ ctc lookalike acme.com --limit 10 --estimate
up to 3.5 credits — nothing spent yet
 
$ ctc verify jane@acme.com
jane@acme.com: deliverable
exit 0
# charged: 0.02 credits

Find the contact
you already know about.

Waterfall enrichment across 20+ premium data sources, behind one command per field. Charged only when a result is found.

Work email finding

Full name plus domain or company in, a verified work email out — with a confidence score and catch-all flag. 1 credit per found address; a miss is free.

$ ctc find "Jane Smith" acme.com

LinkedIn URL enrichment

Already have the profile URL from your CRM or a licensed source? Pass it alone — no company anchor needed. No scraping involved at any point.

$ ctc find <linkedin_url>

Reverse email lookup

One email in, the person and company behind it out: name, title, company profile. 1 credit per resolved profile.

$ ctc whois jane@acme.com

Personal email & mobile phone

Higher-value fields stay intentional: --personal switches find to personal email (3 credits), and phone is its own verb at 10 credits — never an accident.

$ ctc phone "Jane Smith" acme.com

Know it’s deliverable
before you send.

Sub-second verification at 0.02 credits per address, single or batch.

Deliverability verdicts

Each check returns a status — deliverable, undeliverable, risky, unknown — plus a confidence score and a catch-all flag, so a send decision is one comparison.

$ ctc verify jane@acme.com

Free local pre-checks

Syntax and MX validation run locally before any credit is spent. Obvious garbage never reaches the paid check.

$ ctc verify <email> --json

List-scale verification

A CSV in, every row annotated out — batch verify defaults to stdout so it pipes. A 5,000-row list costs 100 credits.

$ ctc verify list.csv clean.csv

Send-time guards

Cheap enough to run at the moment of sending, not just at import: a one-line guard clause in any script or agent loop blocks the bounce before it happens.

$ ctc verify "$EMAIL" --json | jq -r .status

Scoped discovery,
priced per request.

Not a database dump — bounded searches at named accounts and expansion from seeds you trust.

People search

People at a named company, filtered by titles, departments, seniority, or location. 0.25 credits per search request, regardless of rows.

$ ctc search people --domain acme.com --titles "VP Sales"

Company search

Companies by explicit attributes — industry, headcount range, type, location. Returns profiles for you to qualify before spending on contacts.

$ ctc search companies --industry "Software Development"

Lookalike expansion

One seed in, similar records out: a domain returns similar companies, a LinkedIn URL returns similar people. 0.35 credits per returned row.

$ ctc lookalike acme.com --limit 25

Filter introspection

Every accepted filter value — industries, seniorities, company types — printed locally, copy-friendly, for free. No guessed enums, no empty result mysteries.

$ ctc search filters seniorities

A tool an agent
can operate unsupervised.

Designed for the Bash tool, not the browser. Stable contracts everywhere an agent needs to branch.

Self-describing surface

ctc instructions prints the whole operating guide in ~60 lines. An agent reads it once per session — zero standing context cost, unlike resident tool schemas.

$ ctc instructions

Deterministic JSON

Every command supports --json with stable shapes, versioned via the schema field in version --json. Parse once, trust it from then on.

$ ctc find "Jane Smith" acme.com --json

Meaningful exit codes

Found is 0, not-found is 2, budget cap is 4, timeout is 9. Scripts and agents branch on $? without parsing a single byte of output.

$ ctc verify $EMAIL || handle $?

No interactive prompts. Ever.

No command waits for keyboard input — no confirmations, no wizards, no pagers. Safe in CI, cron, and full-auto agent modes by construction.

$ ctc whois inbound.csv out.csv

Files in, files out,
nothing lost.

CSV/TSV batch on the four bulk verbs, with semantics designed for pipelines that run unattended.

Positional batch

Pass a file as the first positional and the verb goes batch; second positional is the output. Row order preserved, input columns untouched, errors reported per row.

$ ctc find leads.csv enriched.csv

Atomic in-place overwrite

Same input and output path? The result is written via temp-file-then-atomic-rename, so a crash mid-run can never corrupt your source file.

$ ctc verify contacts.csv contacts.csv

Resumable async runs

Long jobs return a run-id on timeout instead of dying. Reattach any time — results are waiting and nothing is billed twice.

$ ctc find --run-id <id> out.csv

Automatic backoff

Rate limits answer with a retry-after value, and the CLI honors it: sleep, retry, up to ~90 seconds. Pipelines see latency, never flakes.

$ ctc verify big-list.csv out.csv

Visible before,
capped during, audited after.

Credits are one number. Every mechanism that touches them is explicit.

Free estimates

Add --estimate to any paid command and it prints the cost and exits — computed locally from the embedded price table. Zero spend, zero network.

$ ctc find leads.csv out.csv --estimate

Hard spend caps

Set --max-cost and the run stops before crossing it, exiting 4. A malformed file or runaway loop cannot drain the balance.

$ ctc find leads.csv out.csv --max-cost 100

Charged only when found

find, phone, and whois bill per result, not per attempt. A clean miss costs exactly nothing — and is still reported per row.

$ ctc find "Jane Smith" acme.com

A readable ledger

ctc usage shows the balance split (plan vs top-up) and recent spend, line by line. The dashboard mirrors the same numbers.

$ ctc usage --json

Capabilities are the half of it.

Wondering what they do for the business? Benefits ties each one to an outcome. Curious why this is a CLI at all? The CLI page makes the case.