How a one-person sales team fills the pipeline with daily ICP-matched leads
If you're the entire sales org, the most expensive thing you can do is start the day hunting for someone to call. The rest of the team doesn't notice the wasted hour, but you do — and so do your numbers. This post walks through how a solo rep turns a single saved ICP into a reliable daily pipeline of verified leads, without ever opening a spreadsheet.
Define your ICP once, not every morning
The interesting part of "prospecting" isn't searching — it's deciding who's worth searching for. ProspectJet stores that decision as a single icp_profiles row, keyed to your account, and exposes it through db/icp-profiles.js#getIcpProfileByUserId. Every morning, the matcher reads only that row.
The profile carries five fields: industry_keywords, target_roles, geography, company_size_band, and free_text. The form saves them all, and the page displays them all — but honest disclosure: today, only the first three of those five fields actually narrow the candidate set.
The matcher builds an AND predicate from industry_keywords, target_roles, and geography (the comment block at the top of services/icp-digest.js lists these explicitly as the structural filter keys). That means a rep who sets fintech, VP Sales, United States, 50–200 employees, and a free-text line about "post-Series A" gets a tight funnel on the first three and a documented-but-not-yet-narrowing contribution from the last two. When the leads table grows headcount and notes columns, those inputs will start to constrain the match — until then, the matcher still references them so the persisted criteria stay consistent as the schema catches up.
This is more useful than it sounds. You don't get a "you filled out a field and we ignored it" surprise; you get a candidate set that is reliable enough to email, and a system that will tighten automatically as more columns land.
The nightly cron does the searching for you
Once your ICP is saved, you don't run a search. The platform runs one on your behalf at 8 AM every day. The schedule is declared in polsia.toml as the nightly-icp-digest cron, pinned to 0 8 * * *, posting to https://prospectjet.polsia.app/api/admin/nightly-icp-digest with the shared x-admin-secret header. The handler at routes/admin.js delegates straight to services/icp-digest.js#runNightlyIcpDigest, which queries every customer whose subscription is active, looks up their ICP profile, and pulls the unmatched rows from prospectjet_leads.
For most solo reps this is the only thing they need to remember: the system has a heartbeat, and that heartbeat fires every morning.
Idempotency, not flags
The interesting design choice is what happens the second time the cron runs the same day. Each matched row carries a status column; matching pulls only rows where status = 'new', and on a successful email send the row flips to status = 'delivered' via db/prospectjet-leads.js#markLeadsDelivered. A re-run later the same day finds zero undelivered rows for customers the first run already delivered to, so re-running is harmless — no per-customer sent-flag, no per-day sent-flag, just a row state.
The practical consequence: if the cron crashes at 8:00 and you (or the platform) re-trigger it at 8:15, the second run delivers the rows the first run didn't get to, and customers who already got their digest are unaffected. No one gets a duplicate morning email.
Cadence controls decide how often that email lands
Not every team wants a daily digest. profile.cadence holds one of three literal values — daily, weekly, or paused — set via setIcpCadence on the same profile row. The matcher honors them as follows:
- daily fires the digest every morning, no gating.
- weekly suppresses the digest if the customer already received one in the last 7 days, gated by
CADENCE_WEEKLY_WINDOW_MSinservices/icp-digest.js(usinggetLastDeliveredAtacross the customer'sstatus = 'delivered'rows). - paused skips the customer entirely — no digest, no email.
The manual Email me these leads button on the dashboard is opt-in and intentionally bypasses cadence. That's the right default for a rep who suddenly wants the rest of the queue today: cadence should not be in their way when they actively click a button, only when the system is firing on their behalf.
Why the email is verified before it reaches you
The turnover rate from "raw prospect" to "verified deliverable email" is high enough that delivering matches without a verification step would burn a one-person team's day on bounces. The nightly digest is sourced from the verified side of the pool, which is why the daily digest is small and reliable rather than wide and noisy.
A note on the email side, since it shapes what you can do next: ProspectJet sends through the Polsia email proxy, which has two rate tiers — known-contact (50 sends per day to recipients ProspectJet has previously engaged, including all purchases) and cold-outreach (2 sends per day). Every purchase auto-registers the buyer as a known contact, and there's a retry-on-rate-limit path on cold sends. Translation for a solo rep: the platform's own digests sail through at the known-contact tier, and you won't accidentally burn the cold-outreach budget on a manual outreach habit you haven't built yet.
What the morning actually looks like
At 8:00 AM the cron fires. By 8:05 you have an email in your inbox with a small list of freshly-matched leads — name, company, role, verified email, phone, LinkedIn — where every record was matched against your saved ICP and never sent to you before. You open it at your kitchen table, pick three names, and start the day in conversation rather than in search.
If your week is quieter than usual, switch cadence to weekly and let the digest batch up. If you go on vacation, switch to paused and the queue stops cold. If you come back and want to reload the account in one click, the dashboard button is there.
That's the whole system. One row in icp_profiles, one cron at 8 AM, one status-flip keeping duplicates out, one cadence column shaping the rhythm. The one-person sales team gets a daily verified pipeline, the sales team of one stays focused on conversations, and the morning hour that used to disappear into LinkedIn comes back.
Set your ICP once. Go to bed. Open the email tomorrow.