nvNeuralVerge

CRM Enrichment Agent: Fill Missing Titles, Emails and Headcount Overnight

Use a CRM enrichment API or MCP to fill missing titles, emails and headcount overnight, with checks, a change log and the points each lookup costs.

By the NeuralVerge team · 12 min read · Updated October 2026

▸On this page

A CRM enrichment API takes what a record already holds and returns the fields it is missing. Wrap it in an agent and the loop runs overnight: find records with gaps, pick the right lookup for each, check the answer and write back only what passed. This post shows which fields to target, which lookups answer them, the rules an unattended agent needs and what a night costs. Reach it over REST or MCP.

The short version

  • —What it does: an overnight agent fills three fields that map cleanly to NeuralVerge sources: job title, work email and company headcount. It leaves a field empty when it cannot source it.
  • —Who it is for: teams whose CRM has aged (people change jobs, companies grow) and who want a reviewable change log instead of a one-off file import.
  • —What it costs: points per lookup, printed on each source page: 10 for a LinkedIn profile, 10 for profile plus email, 10 for the email finder, 1 for email validation, 5 for a company profile. A name-and-domain record costs 21 points at worst, 11 with a profile URL on file.
  • —Where to find exact fields: the LinkedIn people profile plus email source page is the reference for request shape, fields and prices.

How the overnight run works

Each step answers one narrow question. The agent does not need to know in advance which lookup will succeed for a record. It runs the sequence, records what came back and moves on. The overnight timing is a scheduling choice: enrichment is not urgent, it is better done when nobody is editing the same records, and a morning skim of the change log gives you a natural review step.

A lookup, a bulk append and an agent are different things

A lookup is one call, one input, one answer; it never touches your data. A bulk append runs a whole file against a vendor and returns a snapshot you then reconcile with a CRM people kept editing. An agent sits in between: it decides per record which lookup suits each gap, checks the answer and writes back under rules you set.

1. Find the gaps

Start in your CRM, not at the data source. Query for records where the target fields are empty or stale: no email, no title, no company size. Order them by value, for example open opportunities first, then recently active accounts. Cap the batch. An overnight job with a ceiling is predictable; one without is a surprise on the invoice.

2. Choose a lookup by what the record holds

  • —A profile URL is on file. The LinkedIn people profile plus email source takes the URL and returns the headline, location and the email where one can be resolved, in one call.
  • —A name and a company, no profile URL. Resolve the profile first with the LinkedIn profile by name and domain source, then continue as above.
  • —A name and a domain, only the email missing. The email finder takes first name, last name and domain and returns an address with a confidence rating.
  • —An account with no size or industry. The LinkedIn company profile returns a headcount band and, where the page gives one, an exact employee count, plus industry, headquarters and open roles.

3. Fill titles from the profile

A job title goes stale fastest and matters most for routing. The profile lookups return a headline, usually the title plus the employer in the person's own words. Treat it as a candidate: "CEO at Acme Oy" is easy to split, while a headline that reads like a slogan should be skipped or sent to review.

4. Fill emails, then check them

The agent tries the cheapest sufficient route. When a profile URL exists, the profile-plus-email source may return the address in the same call that read the title. When it does not, or the address came back empty, the email finder takes over with the name and company domain. Either way, every address goes through email validation before it is written as usable, because a resolved address is not a deliverability guarantee.

5. Fill headcount at the account level

Headcount belongs to the company, not the contact. Deduplicate: look up each account once, then apply the result to every contact under it. The company profile returns the band the company publishes about itself, such as "51-200 employees", and an exact count where the profile gives one. It is a claim, not an audited figure, so store it as a range with the date you read it.

When the question is "who works there" rather than "how big is it", the LinkedIn company employee source searches people at named companies with title, seniority and function filters. It returns a filtered sample, not a roster, so use it to find a missing contact at a target account, not to reconcile a headcount.

6. Write back with a change log

Write only what passed the checks, and record for every change the field, old value, new value, source, session id and time. The log makes the run reviewable, and it lets you undo one night's work without guessing which values the agent touched.

Worked example: one night at Acme Oy

Take a CRM with three kinds of incomplete record, all about the fictional Acme Oy (Finland), an illustrative company.

  1. —A contact with a name and the domain acme.example, and nothing else. The agent resolves the name and domain to a profile, checks that the returned employer is Acme Oy, then reads the profile with the profile-plus-email source. That gives a headline to propose as the title and an address if one resolves.
  2. —A contact with a profile URL and an empty email field. The agent goes straight to the profile-plus-email source. The address comes back empty, so it falls back to the email finder with first name, last name and domain. If the finder returns an address, validation runs before it is stored.
  3. —The Acme Oy account record, with no size. The agent reads the LinkedIn company profile once, stores the headcount band and the date, and applies it to every contact under the account. It stores an exact employee count only if the profile gives one.

By morning the change log shows what was filled, from which source and with which session id. Uncertain matches, private profiles and unresolved addresses are listed as "not filled", not as errors.

One request and the response that comes back

The most useful single call in the loop does two jobs at once: it reads the profile for a title and returns the email in the same request. This is the REST request from the source page.

curl -X POST https://api.neuralverge.ai/functions/v1/run-linkedin-email \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "username": "https://www.linkedin.com/in/example/" }'

The username parameter takes the full profile URL, not a bare handle, and one profile goes in per request. The response below is the real captured sample from the source page, a public executive profile used as the documented example. Nothing is shortened.

{
  "session_id": "11111111-1111-1111-1111-111111111111",
  "kind": "linkedin_email",
  "username": "https://www.linkedin.com/in/sam-altman/",
  "includeEmail": true,
  "human": "# LinkedIn people profile + Email\n\n- **Profile_url:** https://www.linkedin.com/in/sam-altman/\n- **Fullname:** Sam Altman\n- **Headline:** CEO at OpenAI\n- **Location:** San Francisco Bay Area\n- **About:** CEO of OpenAI and former president of Y Combinator.\n- **Email:** sam@openai.com",
  "machine": {
    "total_items": 1,
    "first_item": {
      "basic_info": {
        "fullname": "Sam Altman",
        "headline": "CEO at OpenAI",
        "profile_url": "https://www.linkedin.com/in/sam-altman/",
        "location": {
          "full": "San Francisco Bay Area"
        },
        "about": "CEO of OpenAI and former president of Y Combinator."
      },
      "email": "sam@openai.com"
    },
    "items": [
      {
        "basic_info": {
          "fullname": "Sam Altman",
          "headline": "CEO at OpenAI",
          "profile_url": "https://www.linkedin.com/in/sam-altman/"
        },
        "email": "sam@openai.com"
      }
    ]
  },
  "total_points": 10
}

Read the shape the way the agent does. The machine object is what the code consumes: first_item.basic_info.headline is the title candidate, first_item.basic_info.location is the location, and first_item.email is the address, present when the source could resolve one. The human field is a readable summary of the same data, useful in a log. The total_points field is 10, the whole charge for this call.

Two things matter for an unattended run. The email is returned where it can be resolved, which is not every profile, so the agent must handle a profile with no address. And private or restricted profiles do not resolve at all; the source page says a profile that cannot be read is not billed.

REST and MCP

Both routes reach the same source at the same point cost, so choose by who makes the call. Use REST for a scheduled job that your own code runs. Use MCP when an agent such as Claude decides which lookup to call, in which case the lookup above is the tool run_linkedin_email with the same username argument. The email finder (run_email_finder), email validation (run_email_validation), LinkedIn company profile and LinkedIn company employee sources are likewise available over both. AI research is the one exception, because it runs over REST only. For connecting a client and listing the tools, see using NeuralVerge as an MCP server for Claude. For the single-source view of every LinkedIn lookup, see the LinkedIn enrichment overview.

Cost and limits

Every lookup is priced in points, and the number is printed on the source page. These are the ones this agent uses, from the source pages at the time of writing.

LookupFillsPointsOn a miss
LinkedIn profile by name and domainThe profile URL10 per matched profileAn unresolved name is not billed
LinkedIn people profile plus emailTitle, location, email10 when the profile resolvesAn unreadable profile is not billed
Email finderWork email10 when an address is foundA miss costs nothing
Email validationVerdict, catch-all flag1 per checkCheck the source page
LinkedIn company profileHeadcount band, industry5 per companyA company not found is not billed
LinkedIn company employeeMissing stakeholders30 per run, plus 5 per profile (10 in full mode)A run with nobody returned is charged only the run

The arithmetic is simple enough to do before you start. A record with only a name and a domain that goes through the full chain (resolve the profile, read it with the email step, validate the address) costs 10 + 10 + 1 = 21 points in the worst case. A record that already has a profile URL costs 11. An account lookup is 5 points and is paid once per company, however many contacts sit under it. For what a point costs on your plan, see the pricing page.

Limits worth stating plainly

Cost is not the main risk of an overnight agent. Correctness is.

  • —Not every record resolves. Small companies, sparse profiles and common names at large employers are the hard cases. Leave those fields empty rather than guess.
  • —A headline is not a verified title. It is what the person published about themselves.
  • —Headcount is self-reported. If you need a legally verified fact, join it with the corporate registry record.
  • —Sources are read at request time, so the same lookup tomorrow can return a different answer. The change log is how you tell a correction from a regression.

Rules for an unattended agent

An agent that writes to a system of record without a human watching needs stricter rules than one that drafts for review. Write these down before the first run.

  1. —Fill empty fields, propose changes to populated ones. A sales rep may have corrected a title by hand. The agent cannot know that, so it leaves populated fields alone and queues a suggested change.
  2. —Match before you trust. A name and a company can match two people. Compare the returned employer to the account's domain or name, and drop the result if they disagree. A wrong person's email in the right account is worse than an empty field.
  3. —Validate before marking an email usable. Store the verdict and the catch-all flag next to the address, so a sequencer can filter on them later.
  4. —Keep the source and the date on every value. A field written without provenance cannot be audited, and a headcount band from last night is not the same as one from last year.
  5. —Cap the batch and the spend. Set a maximum number of records and a maximum number of points per run. When either is reached, the agent stops and reports rather than continuing.
  6. —Respect opt-outs. A contact marked do-not-contact stays out of the batch. These sources return personal data, so use them for legitimate business purposes under your own lawful basis, honour deletion requests and read the acceptable use policy. This is not legal advice.

How to decide

  • —What happens on a miss? Confirm the agent leaves the field empty, logs the reason and does not retry forever. Check the billing line on each source page for what a miss costs.
  • —Do you validate emails before writing them as usable? The 1-point check is cheap relative to a damaged sending domain.
  • —Can you undo a night? A change log with old and new values, source and session id is the difference between a rollback and a week of reconciling by hand.
  • —Is the batch capped in records and in points? An uncapped job turns one bad query into an expensive morning.
  • —Do you have a lawful basis for the contacts you enrich? Check that before the first run, not after.
  • —Is the job a fit? It suits cleaning a list before a campaign (titles and emails so seniority segments have something to segment on), routing inbound sign-ups that arrive with only a work email, refreshing contacts on open opportunities and flagging changed employers (often the first sign a champion has left), and finding a missing stakeholder at an account with one contact.

Frequently asked questions

Which fields can an overnight CRM agent realistically fill?

Job titles, work emails and company headcount are the three that map cleanly to NeuralVerge sources. Titles come from the LinkedIn profile lookups, emails from the LinkedIn profile plus email source or the email finder, and headcount from the LinkedIn company profile. Each source returns what it can find, so some records will still come back with a field empty.

How much does a nightly enrichment run cost?

Each lookup is priced in points on its source page: 10 for LinkedIn profile by name and domain, 10 for LinkedIn people profile plus email, 10 for the email finder, 1 for email validation and 5 for the LinkedIn company profile. Misses are not billed on the profile and finder sources. Multiply the points by the number of records you expect to touch, and check the pricing page for what a point costs on your plan.

Should the agent overwrite existing CRM values?

Not by default. A sensible agent only fills empty fields, and proposes a change to a populated field for a human to review. A person may have corrected a title by hand, and an automated overwrite cannot know that.

Can I run this over MCP instead of REST?

Yes. Each of these lookups is available over REST and as an MCP tool, and both routes run the same source at the same point cost.

Is a found email safe to send to?

Not until it has been checked. A found or resolved address is a candidate, not a deliverability guarantee. Running it through email validation costs 1 point and tells you the verdict, whether the domain is a catch-all and a confidence rating before the address reaches a sending domain you care about.

Is it legal to enrich contacts this way?

Contacting people is regulated where you operate, not where the data sits. You need a lawful basis, you should honour opt-outs and deletion requests, and you should read the acceptable use policy. This is not legal advice.

About NeuralVerge

Give your agents structured, cited, real-world data from 300+ sources and the open web — through one API or MCP server.

Data Sources on the NeuralVerge blog.