salesascode
← All feature docs
Feature docs · /enrichment

Contact Enrichment

Fill a contact's missing facts by walking your providers cheapest first, stopping per field on the first valid hit, with the full spend trail shown.

Included with gtmcron . A seat without it sees an upsell here instead of the page.

Overview

Contact Enrichment runs the enrichment waterfall for a single contact: you enter what you know, and the cascade walks your configured providers cheapest first, filling each missing field on the first valid hit and stopping there so no field is paid for twice. It is the interactive front end to the same waterfall primitive the scheduled runs use, so what you see here matches what the agents get.

What it is for, on the page. Under the headline, this page says what it produces, what makes it run, and where the output lands. Every Work page reads that line from one registry, so the three answers cannot drift from the page.

How the waterfall works

You supply at least a name, a LinkedIn URL, or a company domain, and choose which fields to fill (email, phone, title, seniority, company, LinkedIn, employee count, industry). Press Enrich contact with none of the three filled in and the page says so under the button and puts the cursor in the name field; untick every field and it says that instead and moves you to the first checkbox. The cascade asks each provider only for the fields still missing, in cost order, and writes the first valid value it gets. Email values pass a deliverability check before they are returned; an email that fails is rejected and the chain keeps looking. The result shows every filled field with the provider that supplied it, the credits spent, and a per-provider trail (hit, miss, skipped, not-configured, error) so the spend and coverage are fully auditable.

Role inboxes and catch-all domains. Passing the deliverability check only means the domain takes mail. Under the filled facts, the email also says whether it is a shared role inbox (info@, sales@, support@ and similar) and whether its domain accepts mail to any address. The second comes only from the provider that found the address: Hunter reports it on every lookup, Apollo only when its response carries it, and otherwise the page says the provider did not report it. Nothing here connects to a mail server to find out. Either flag keeps the address on the contact but holds its drafts: the morning queue writes none, and lists the contact under Drafts ready to send on Activity, where you can approve the address.

Every address gets a verdict

Each address on a prospect or contact carries one verdict, and each verdict has one rule. The tiles under the run count them, the Contacts table shows the verdict per row (hover it to see who checked the address and when), and Held addresses lists every address that is waiting.

VerdictWhat it meansWhat happens
ValidA verifier said the address takes mail, and nobody reported the domain as catch-all.Sends.
Catch-allThe domain accepts mail to any address, so the address proves nothing about whether a person reads it.Held until you approve that exact address. A different address on the contact is checked again.
UnknownA verifier ran and could not say.Held. Checked again after 7 days, at most twice, then it stays held. Re-verify checks it now for one credit.
InvalidBad syntax, no mail server on the domain, a throwaway inbox domain, or a verifier said undeliverable.Never sent, and it cannot be approved. Find another address.
UncheckedNo verifier has seen it: none is connected, it is not switched on yet, or your credit budget was spent.Sends as before, unless you turn on Require a verified address before sending.

The same rule runs at draft review and at the moment of sending, so an approved draft to a held address is still refused (the send gate lists it as Address verdict). The morning queue writes no draft to a held address and names the verdict on the held card.

The verifier. After a provider finds an address and it passes the mail-server check, a verifier checks it before it is saved. Each check costs one credit from the same budget as the providers, and with the budget spent nothing is checked and nothing is charged. The first verifier uses your Hunter key. It is in preview and not switched on yet, so until it is every new address reads unchecked and the run says why. Nothing here opens a connection to a mail server itself.

Personal addresses. An address on a personal mail domain (gmail.com, outlook.com, icloud.com and a short list of others) is kept on the contact as a personal address and never used for a cold send. When the contact's company domain is known, the providers are asked for a work address there instead. If none is found the row reads Personal address only: the contact can still be called from the dial list if a phone number is on record, and gets no email draft.

Unreachable contacts. A contact with no address that can take a draft and no phone number cannot be reached. The morning queue skips it before writing anything and counts it as unreachable in its run summary, so no AI call is spent on a draft nobody can receive.

Honest by default

A provider with no credentials is reported as not-configured and never called, so it costs nothing and fabricates nothing. If you have not connected any enrichment providers yet, every provider shows not-configured and the result is empty, that is the honest state, not an error. As each vendor path is verified and its credentials are added, the same panel gets stronger with no change to how you use it. Add provider credentials in Settings under Connect your tools.

A provider we did not call reads as its own state, deliberately not as "no record". A no-record result says the vendor was asked and had nothing, which is a fact about your contact. The other says we did not ask, which is a fact about us. Nothing is charged either way, and the panel now names the reason per provider rather than lumping them together, because the reasons differ and only some of them are yours to act on.

The chain is Hunter, then Apollo, then Sumble, and each is called for real once you add a key: sign up, generate a key, paste it. Hunter and Apollo fill the person. Sumble knows companies, not people, so it fills only employee count and industry, and is asked only when you tick one of those. Sumble is billed per matched company (one credit plus one per field), and an unmatched domain is free.

Three vendors are not in the chain at all, and every result lists them under Not in this chain with the reason, so a thin result is never read as having asked them. ZoomInfo and Cognism publish their enrichment API only under a partner agreement, so there is nothing we can call without guessing at its shape. Clay enriches asynchronously inside a Clay table, so it runs through the Clay connection (context goes to your table and the enriched row comes back through its signed webhook), not through this page.

Spend counts against your cap

Every run is charged against the same credit budget the scheduled re-enrichment uses, so the cap you set on Enrichment Budget governs this button too. With the budget used up, nothing is requested and nothing is spent, and the panel says so rather than showing an empty result. Only credits a provider actually reported are charged, which is zero for a provider we did not call.

A provider that runs on our key rather than yours also draws on the monthly platform allowance described on Enrichment Budget. When that is used up, the provider is not called, its row reads "platform allowance used", and a note above the results says when it resets. Providers on your own keys still run.

If we cannot read your cap at all, the run is refused the same way, and the credits tile reads "cap unknown" instead of "no cap set". Those are different answers: one is a setting of yours, the other is a failure of ours, and we will not spend a vendor credit against a cap we could not check. Try the run again in a moment.

What Hunter fills, and why it goes first

Hunter answers one narrow question well: what is this person's address at this company. Give it a first and last name plus a domain or company name and it returns the work email with a confidence score, and the job title and company name arrive on the same response at no extra cost.

It goes first in the cascade because it is the cheapest and narrowest. Email is the field asked for most often and the one a draft is useless without, so answering it before a broader provider is asked is what cost order is for. Whatever Hunter leaves open falls straight through to Apollo, which is then asked only for the rest.

An address below Hunter's own confidence boundary is not written. Hunter returns a pattern-matched guess with a low score rather than nothing, and accepting that would fill the field with an invention and stop the cascade from asking a provider that actually knows. The guess is discarded, the field stays open, and the next provider is asked.

It does not fill a phone number, seniority, headcount or industry. Those are not fields Hunter has, so they fall through rather than come back blank. Hunter bills the request whether or not it finds an address, so a miss is charged to your budget and the panel shows it, which is the honest reading of what a run cost.

What Apollo fills, and what it does not

Apollo can fill the work email, title, seniority, LinkedIn URL, and the company's name, industry and headcount. A person it has no record of costs nothing; a person it matches costs one credit whether or not we could use what came back, because that is what Apollo bills for.

It does not fill a phone number here. Apollo reveals phone numbers asynchronously: it takes the request, returns a ticket, and delivers the number later. This page answers while you wait, so asking would spend credits on something it cannot collect. The phone field falls through to the next provider instead, which is the honest outcome rather than a silent blank. Apollo also returns a placeholder address for an email your plan has not unlocked; that is dropped rather than written to your contact, so the field stays open for another provider.

What a run leaves behind

Since 12 September 2026 a run is written where it was for. Pass a record (persist: { entity, id }, a prospect, contact, account or target account) and the filled facts land on it: each field at the top level where the record had none, so a value you typed is never overwritten, the whole result under enrichment with the provider per field, and one dated line on the record's research log saying which fields, from whom, at what cost. The scheduled re-enrichment writes the same line. Research passes on a contact or an account write theirs. The log keeps the newest twenty.

When the record came from a connected CRM (its id says so: an Attio person, a HubSpot deal, a Salesforce contact, a Pipedrive person), the same line is pushed there too, as a note, a task or an activity through the write-back adapter for that CRM. Attio gained a note adapter for this; it is marked preview until it has run against a live workspace.

The shared pool. Before a run spends a credit, the cascade reads the platform's pool of company facts for the contact's domain and seeds what it already holds (company, industry, headcount), so those fields cost nothing. The pool is built from what tenants who opted in found: company facts and dated findings with a public source, keyed on domain, with no tenant id and nothing about a person. Turn contribution on under Connect; reading is on for everyone. The response says which fields the pool seeded (poolSeeded) and whether this run contributed (contributed).

When the pool is trusted. A fact seeds a run only once two or more accounts have contributed the same domain: one contribution is one vendor's answer copied once, two is corroboration. A row with a single contributor is read and not settled, so the cascade still asks a vendor. Sourced findings are different: each carries the public page it came from, so the account-research pass cites them as prior evidence at any contributor count, marked stale until a fresh read confirms them, and the rep checks the page rather than the count.

What it does not do

Contact Enrichment fills facts for one contact on demand; it does not bulk-enrich a list. It reads what you type into the form and returns the filled facts to the page, and stores them only when you name a record to write to. Bulk re-enrichment on a schedule stays with the gtmcron scheduled runs, which call the same waterfall over your book. The design mockup drew this as a bulk cascade dashboard with rows-in and coverage-percent aggregates across thousands of rows; those are omitted here rather than fabricated, because this endpoint is single-contact. The per-contact provider cascade shows the same walk honestly for the one contact.