For the complete documentation index, see llms.txt. This page is also available as Markdown.

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:

  1. Someone submits a form with their work email.

  2. Submit their workEmail, and companyDomain if you have it, to the Contact Enrichment API.

  3. Store the returned requestId.

  4. Check the request status until it is COMPLETE or ERROR.

  5. 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 ID

  • hubspot: 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:

Status
Description

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:

  1. Submit a person using POST /enrichment/enrich-contact/request.

  2. Store the returned requestId.

  3. Poll GET /enrichment/enrich-contact/request/{requestId} every few seconds.

  4. Continue polling while the status is QUEUED or IN_PROGRESS.

  5. When the status is COMPLETE, check result.found. COMPLETE also covers requests where Goodfit couldn't resolve the person.

  6. For ERROR, inspect error.

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

Field
Description

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:

  • matchedBy says how Goodfit identified the person: linkedInUrl, workEmail, crmRecord or name. name means a match on the name and company you gave rather than an exact identifier, so it's worth a check.

  • inputs echoes back your identity in the canonical form used for matching, so you can confirm what was actually looked up.

  • startDate is the start of the employment, as YYYY-MM-DD.

  • isFormerEmployment is true when 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.

  • addedToDataset is true when this request added the record to your dataset, and false when it was already there.

  • company.addedToDataset is true when 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:

Value
Description

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

Reason
Description

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 externalIds value 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