How does Clean fields work?
Clean fields is a bulk action in the database selection bar that runs an LLM diff pass over selected prospects, looking for empty + malformed fields, and proposes corrections. Two modes:
- Review-first (default) — Suggestions surface in a diff modal where you accept or skip per-row.
- Auto-apply — Toggle on
/settings#bulk-actions. High-confidence non-lookup-required suggestions apply immediately; the rest still surface for review.
Cost: 2 usage units per prospect. Solo / Pro / Enterprise tier required (free returns a 402 with an upgrade hint).
What it cleans
The LLM scans these fields per prospect:
name,first_name,last_nametitlecompanyemail,phonelinkedin_url
Detection cases:
(a) Empty fields derivable from other fields.
- first_name / last_name from a populated name (split by whitespace)
- email derivable from a known company domain + name (only with high confidence; anything speculative gets flagged requires_lookup)
(b) Malformed fields.
- Phone with no separators or with letters (e.g. 5555551234 → (555) 555-1234)
- Email lacking @ or with obvious typos in the domain
- LinkedIn URL missing slug or pointing at the homepage
- Title in ALL CAPS or all lowercase when it should be Title Case
- Name missing capitalization (jane doe → Jane Doe)
- Company missing capitalization
Out of scope here: industry / HQ / headcount band / company info → those use Enrich → Company info (Firecrawl scrape + LLM extract, 2 units/prospect).
The review flow
After the LLM pass returns suggestions, the diff modal shows one row per (prospect, field) with columns:
| Column | Meaning |
|---|---|
| Checkbox | Accept this suggestion. Disabled when requires_lookup is true or the LLM returned no value. |
| Prospect / field | Who it's for, which field, the LLM's reason |
| Current | What's there today (or (empty)) |
| Proposed | The corrected value |
| Conf | LLM confidence 0–100 |
Use Select all / Deselect all at the top to bulk-toggle, then Apply selected to commit.
Apply is one POST to /api/prospects/clean-fields/apply. Only the fields you accepted are updated. Prospects you didn't tick are untouched.
The "requires lookup" flag
When the LLM can't propose a confident value without external data (e.g. it doesn't know the prospect's email but says one likely exists), it flags requires_lookup: true and proposes nothing. These rows render at low opacity with a "REQUIRES LOOKUP" badge and never auto-apply — even with auto-apply mode on. Use Enrich… to actually look those up.
Auto-apply mode
Toggle on /settings#bulk-actions. When on:
- The endpoint runs the LLM pass and immediately applies safe suggestions:
requires_lookup=FalseAND non-nullproposed_valueANDconfidence ≥ 70. - The diff modal is skipped.
- A summary toast shows how many fields were applied + how many prospects.
- Anything not auto-applied (low-confidence or lookup-required) surfaces in a follow-up review modal you can open from the toast.
Recommended for high-volume cleanup workflows where you trust the LLM's casing / format fixes. Keep it off if you want to eyeball every change before it lands.
Pricing math
50 prospects × 2 units = 100 units. The estimate is flat — there's no live preview endpoint because the math is just multiplication. The cost preview in the modal mirrors this: <count> × 2 units = <total>.
LLM call routes through agents.usage.charge_and_run with task_type='clean_fields'. Every prospect that gets analyzed writes a usage_ledger row, so the /settings/usage history shows exactly what was spent and on which records.
A pre-LLM lint short-circuits to 0 units when the record's already well-formed (correct casing, valid email regex, valid phone characters, valid LinkedIn URL pattern). You won't get charged 2 units per prospect on a pre-cleaned book.
Async path (>100 prospects)
Selections over 100 queue a bulk_clean_fields job in the worker. Track progress at /api/bulk-jobs/<id>. The result_summary stores the full suggestion set so the diff modal renders correctly when you come back to the job.
Cancel works on queued state only — running jobs commit per-prospect progress so cancel returns "already running" once the worker has dispatched the job.
Ask it on the help page and the assistant answers from the whole corpus. If it cannot, team@dealarena.io can, and the answer usually becomes a doc.

