Contacts
The Contact Enrichment API takes a single person you already have a handle on and returns their verified identity, current employment, work email and, optionally, a mobile phone number.
Persona searches find contacts for you across a whole segment. Use this API when you already know exactly who you want, such as a webform signup, a name from an event list or an existing record in your CRM, and you just need the rest of their details.
The contact is added to your Goodfit dataset and can be synced straight back to your CRM, so the person stays up to date alongside everyone else Goodfit maintains for you.
Identify the person with identity.linkedInUrl, identity.workEmail, or identity.firstName + identity.lastName + a company (identity.companyDomain or identity.companyName). Everything else is optional. A name is only tried when no LinkedIn URL or work email was given, or when they found no one. Matching on a name with no company is not supported.
This is an employment API. It returns a person at a company, not a standalone person record. Job title, start date and work email all describe that specific employment.
Common use cases
Enrich webform signups
Fill in the full details of people who reach you through forms, demo requests or product signups.
A typical flow is:
Someone submits a form with their work email.
Submit their
workEmail, andcompanyDomainif you have it, to the Contact Enrichment API.Store the returned
requestId.Check the request status until it is
COMPLETEorERROR.Use the result in your workflow, or let Goodfit write it to your CRM.
Enrich contacts created directly in your CRM
Contacts created directly in Salesforce or HubSpot can be enriched and written back to the same record.
Provide the record ID using externalIds and set syncToCRM: true. Goodfit then updates that exact record rather than creating a second contact. See Syncing to your CRM.
Supported external IDs are:
salesforce: Salesforce contact IDhubspot: HubSpot contact ID
Salesforce IDs can be either 15 or 18 characters; 15 character IDs are expanded to 18. HubSpot IDs must be numeric.
The corresponding CRM connector must already be enabled for your Goodfit account.
Look up people from an event list
Enrich attendees and leads collected at events and webinars. Submit each person with their linkedInUrl or workEmail, plus companyDomain where you have it, and poll each requestId. If you only have names, send firstName, lastName and companyDomain (or companyName), plus jobTitle if you have it.
For longer lists, pace your requests to stay within the rate limit.
Integration patterns
Asynchronous enrichment
Contact enrichment is asynchronous, because finding and verifying someone's details takes longer than a single HTTP request should wait.
A successful request returns a requestId immediately. Use that requestId to check the status of the request until processing finishes.
Requests typically complete within one to two minutes.
The possible status values are:
QUEUED
Request is accepted but not started yet
IN_PROGRESS
Request is being enriched
COMPLETE
Enrichment finished; result is present
ERROR
Enrichment failed; error explains why. Safe to resubmit
A typical integration flow is:
Submit a person using
POST /enrichment/enrich-contact/request.Store the returned
requestId.Poll
GET /enrichment/enrich-contact/request/{requestId}every few seconds.Continue polling while the status is
QUEUEDorIN_PROGRESS.When the status is
COMPLETE, checkresult.found.COMPLETEalso covers requests where Goodfit couldn't resolve the person.For
ERROR, inspecterror.
If you asked for a CRM sync, that follows once the enrichment completes.
Send the company whenever you have it
Someone can hold more than one role. Sending companyDomain on the first request identifies the right employment in almost all cases. Without it, a person with several roles comes back as MULTIPLE_EMPLOYMENTS_FOUND and you need to resubmit. See Handling multiple employments.
Retry safely
Submitting the same contact twice is safe. If an identical request is still in progress, the API returns 200 with the existing requestId rather than creating a second request, so a retrying integration never duplicates work or spends credits twice. Poll the returned requestId either way.
Changing enrichPhoneNumber or syncToCRM makes it a different request, so asking for a phone number after an email-only request is always honoured.
A 402 is returned before any work starts, so retrying after a top-up is safe.
Identifying the person
identity.linkedInUrl
A LinkedIn profile URL. Any common form is accepted
identity.workEmail
Must be a company address; personal email domains are rejected
identity.companyName
Identifies the employment, or the company for a name lookup
identity.companyDomain
Optional hint, reduced to a registrable domain. More reliable than companyName
identity.firstName
With lastName and a company, identifies the person by name
identity.lastName
With firstName and a company, identifies the person by name
identity.jobTitle
Optional. Helps pick the right person when several share a name
identity.selectedCandidateId
The person you picked from a MULTIPLE_PEOPLE_FOUND response
identity.selectedCompanyId
The employment you picked from a MULTIPLE_EMPLOYMENTS_FOUND response
enrichPhoneNumber and syncToCRM both default to false, so a request that omits them enriches the email only and leaves your CRM untouched.
Results
A resolved contact comes back with their name, LinkedIn profile, job title, employment start date and work email, plus the company they work at. A mobile number is included when you asked for one and Goodfit found it.
Contacts added this way behave like any other contact in your dataset: they're refreshed automatically, and if someone changes role or leaves, their details are updated.
A few fields are worth calling out:
matchedBysays how Goodfit identified the person:linkedInUrl,workEmail,crmRecordorname.namemeans a match on the name and company you gave rather than an exact identifier, so it's worth a check.inputsechoes back your identity in the canonical form used for matching, so you can confirm what was actually looked up.startDateis the start of the employment, asYYYY-MM-DD.isFormerEmploymentistruewhen the person has left the company you asked about. Goodfit still resolves them, so you can see who they were and act on the change.addedToDatasetistruewhen this request added the record to your dataset, andfalsewhen it was already there.company.addedToDatasetistruewhen the company was new to you and Goodfit added it. A newly added company appears immediately with core firmographics only; scores, segments and the rest of its data arrive with your next daily sync.
personas and markets are part of the contract but not yet populated, as persona and market matching for this API are still being built. They are empty rather than NOT_FOUND, so you can tell "not built yet" from "looked and found nothing".
Email and phone values
Every resolved contact is enriched for a work email. A mobile number is looked up only when you set enrichPhoneNumber. Three sentinel values tell the cases apart:
NOT_FOUND
Searched, nothing available
NOT_REQUESTED
Not asked for (mobilePhone only)
SKIPPED_EX_EMPLOYEE
Skipped, the resolved employment is one they have left (workEmail only)
Enrichment is best effort. If a lookup fails, Goodfit still returns the resolved contact with NOT_FOUND in place of the value, and the request doesn't fail.
Returned emails carry the same verification statuses as every other email Goodfit supplies. See Email and Phone enrichment.
Unresolved requests
When Goodfit can't resolve the person, found is false and reason gives a machine-readable reason. You aren't charged when Goodfit can't deliver a contact.
Reasons
PERSON_NOT_FOUND
No person matches the identity you gave
MULTIPLE_EMPLOYMENTS_FOUND
The person was found but holds several roles
NO_COMPANY_MATCH
The person was found but couldn't be tied to a company Goodfit can serve
NOT_ENOUGH_INFORMATION
The identity was too thin to search on
COMPANY_HAS_NO_DOMAIN
Their employer has no website domain
COMPANY_RESOLUTION_CONFLICT
The employer found conflicts with the CRM record you supplied
CONTACT_RESOLUTION_CONFLICT
The CRM record you supplied belongs to a different person
CRM_RECORD_NOT_FOUND
The CRM record you supplied in externalIds isn't in your CRM
NAME_NOT_FOUND_AT_COMPANY
No one with that name was found at that company
COMPANY_DOMAIN_NOT_FOUND
Goodfit doesn't recognise the companyDomain you gave
COMPANY_NAME_NOT_FOUND
Goodfit doesn't recognise the companyName you gave
MULTIPLE_PEOPLE_FOUND
Several people at that company fit the name
MULTIPLE_EMPLOYMENTS_FOUND and MULTIPLE_PEOPLE_FOUND are the two reasons you can act on directly. See Handling multiple employments and Handling several matching people.
The two conflict reasons mean your request and your CRM disagree about who or where this person is. Rather than guess, Goodfit refuses the request. It's worth resolving in the CRM before retrying.
COMPANY_HAS_NO_DOMAIN means Goodfit identified the person, but their employer has no website domain. This is commonly a LinkedIn placeholder page (for example "Confidential Government") or a subsidiary with no site of its own. Companies are keyed on domain in your dataset, so this one can't be added and the contact couldn't be attached to it. Retrying won't help. If the person in fact works at a company you can name, supply that companyDomain.
Syncing to your CRM
Set syncToCRM: true and Goodfit writes the enriched contact to every connected CRM that has contact sync enabled, normally within five minutes of submission. The result carries syncedToCRM and, under externalIds, the record ID in each CRM.
How Goodfit chooses the record to write to:
If you send an
externalIdsvalue Goodfit recognises, Goodfit updates that exact record.If you send one Goodfit hasn't seen before, Goodfit adopts that record and updates it rather than creating a second contact.
If you send none, Goodfit looks for an existing contact on the work email, using whichever CRM field you have mapped to email in Data Points, and only creates a new record when there's no match. Goodfit searches your CRM by the mapped email field only.
Two cases are deliberately refused rather than guessed at, and appear on your Connector Logs page:
the ID you sent points at a different record from the one Goodfit already has this person linked to;
several contacts in your CRM share the email, so there's no single right record to update.
Credit usage
Enrichment through this API draws on the same credits as a persona search:
One contact credit per contact added to your dataset. The work email is included and isn't charged separately.
One phone credit if a mobile number is found. Nothing is charged when Goodfit can't find one.
Nothing is charged when Goodfit can't deliver a contact, so an ambiguous or not-found result costs you nothing. As with persona searches, you're only charged once for each unique person at a company. Re-running the same request, or enriching someone a persona search already found, charges nothing. See Contact Credits.
Goodfit checks your balance before starting work, so a request you can't pay for is rejected up front rather than half-completed. Asking for a phone number requires both contact and phone credits.
A contact credit is charged for every contact delivered, including when the person turns out to have left the company. The result is returned with isFormerEmployment: true and is charged as normal.
API reference
For authentication, API keys, base URLs, rate limits and common API errors, see API introduction.
For exact request and response schemas, field definitions and validation behaviour, refer to the API reference pages or OpenAPI specification.
Last updated