---
name: moltsets-batch-enrich-linkedin-list
description: Use this skill when the user has a list of LinkedIn URLs (10 or more) and wants to bulk enrich them with contact data.
---

# Batch Enrich LinkedIn List

Bulk enrich a list of up to 100 LinkedIn URLs. Email lookups run as parallel per-URL calls; phone runs as a single batch array call. Credit pre-check required.

## Triggers

"I have a CSV of LinkedIn URLs", "enrich this list", "bulk enrich", "get emails for all of these", "enrich my Sales Nav export", "process this list". Handles large lists with mandatory credit pre-check, the phone batch chunked at 100, and a hit-rate summary. For 1–9 URLs, enrich-contact is simpler.

## Set Expectations

Before firing any calls, give the user a brief, dry heads-up. Deadpan over enthusiastic - no filler, no corporate speak.

Facts to work with (scale to list size and tools selected). Email lookups are N parallel single calls; phone is a single array call (chunked at 100):
- ≤10 URLs: ~10–20 seconds
- 11–50 URLs: ~30–60 seconds
- 51–100 URLs: ~60–90 seconds, phone in one array call of 100
- >100 URLs: phone runs in array calls of 100, a few minutes - note you'll report after each chunk

Include the URL count, which data types are being fetched, and roughly how long it'll take.

## Step 1 - Parse input

Accept:
- Line-separated paste
- Comma-separated list
- CSV (extract the LinkedIn URL column)

Deduplicate and normalise. Flag malformed URLs separately.

Report: "Found X unique LinkedIn URLs."

## Step 2 - Credit pre-check (required before every batch)

Call `MoltSets:get_billing` and `MoltSets:get_usage` with `period: billing_cycle` in parallel (both free).

Calculate:
```
X URLs × [cost per tool] × [tools selected] = estimated cost
Current balance: Y credits
Remaining after: ~Z credits
```

Note: "not found" results are free - personal email hit rates (~25–40%) are lower than business email (~60–75%). Adjust estimate accordingly.

**If estimated cost > balance:** stop. Report the shortfall, how many rows the balance covers, and ask whether to proceed partially, prioritise a subset, or wait for a top-up.

## Step 3 - Choose what to enrich

| User says | Run |
|---|---|
| "email" (unspecified) | `linkedin_to_best_email` (hybrid - business preferred, personal fallback) |
| "business email" / "work email" | `linkedin_to_business_email` only |
| "personal email" | `linkedin_to_personal_email` only |
| "phone" / "mobile" | `linkedin_to_mobile_phone` only |
| "everything" / "all contact info" / no preference | All three in parallel |

## Step 4 - Fire the calls

- **Email tools** (`linkedin_to_best_email` / `linkedin_to_business_email` / `linkedin_to_personal_email`): one call per URL with `linkedin_url`. There is no array param - fire these in parallel across the list.
- **Phone** (`linkedin_to_mobile_phone`): pass the `linkedin_urls` array (max 100). If the list > 100, split the phone calls into chunks of 100 and process sequentially. Inform the user: "Processing phone in X batches of 100."

## Step 5 - Present results

| LinkedIn URL | Business Email | Personal Email | Mobile |
|---|---|---|---|
| linkedin.com/in/janesmith | jane@acme.com | Not found | +1 415 555 0192 |

**Hit rate summary:**
```
Business emails: 34/50 (68%)
Personal emails: 12/50 (24%)
Mobile numbers:  21/50 (42%)
Estimated credits used: ~XXX
```

## Edge cases

- Mid-batch credit exhaustion: stop immediately, output completed rows marked clearly, report exact resume point
- Malformed URLs: skip and list in a "skipped" section at the end
- Slugs without full URL to construct `https://www.linkedin.com/in/<slug>` before passing
