> For the complete documentation index, see [llms.txt](https://docs.goodfit.io/goodfit-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.goodfit.io/goodfit-docs/apis/enrichment-api/companies.md).

# Companies

The Company Enrichment API lets you submit companies to Goodfit for enrichment using a domain or email address.

It is designed for companies that were not originally supplied by Goodfit, such as inbound leads, event attendees or companies created directly in your CRM.

Goodfit enriches each company using the same data points configured for your Goodfit dataset. Once processing is complete, the enriched company is added to your Goodfit dataset and can be synced to your CRM where a supported connector is enabled.

If both a domain and email are provided, the **domain takes precedence**.

### Common use cases

#### Enrich inbound companies

Enrich companies as they arrive through forms, product signups, routing tools or other inbound workflows.

A typical flow is:

1. A new company enters your workflow.
2. Submit its domain or email address to the Company Enrichment API.
3. Store the returned `requestId`.
4. Check the request status until processing finishes.
5. Retrieve the resulting company from your Goodfit dataset.

This is useful when you want to qualify or route inbound companies using the same data and market definitions already configured in Goodfit.

#### Fill gaps in an enrichment waterfall

Use Goodfit as one step in a wider enrichment process.

For example:

* Check whether you already have the company and the data you need.
* If data is missing, submit the company to Goodfit.
* Wait for enrichment to complete.
* Retrieve the enriched company from the Dataset API.
* Continue the company through your workflow.

This works well with tools such as Clay, n8n or your own internal enrichment pipeline.

#### Enrich companies created directly in your CRM

Companies created directly in Salesforce or HubSpot can be submitted to Goodfit to populate the same company data available across the rest of your dataset.

If you already know the corresponding CRM record ID, provide it using `externalIds`. This links the enrichment directly to that CRM record rather than relying on Goodfit's standard domain matching.

Supported external IDs are:

* `salesforce` — Salesforce account ID
* `hubspot` — HubSpot company ID

Salesforce IDs can be either 15 or 18 characters. HubSpot IDs must be numeric.

The corresponding CRM connector must already be enabled for your Goodfit account.

By default, an external ID is only applied when the company is not already linked to a CRM record, or when its previous sync failed. Use `forceOverrideExternalIds` where you explicitly need to replace an existing link.

If an external ID is invalid, or refers to a CRM without an enabled connector, Goodfit ignores the ID and continues enrichment using its standard matching logic.

#### Enrich event or campaign accounts

Use the API to enrich companies discovered outside your existing Goodfit dataset, including:

* Event and webinar attendees
* Partner-supplied account lists
* Campaign responses
* Product signups
* Rep-sourced accounts
* External directories

This lets those companies enter the same Goodfit data and qualification workflow as the rest of your dataset.

### Integration patterns

#### Asynchronous enrichment

Company enrichment is asynchronous.

A successful request starts an enrichment job and returns a `requestId` rather than the enriched company data itself.

Use that `requestId` to check the status of the request until processing finishes.

Enrichment requests are normally processed within **24 hours**, although processing time can vary.

The possible status values are:

| Status      | Description                                               |
| ----------- | --------------------------------------------------------- |
| `Queued`    | Request is scheduled for processing                       |
| `Completed` | Enrichment completed successfully                         |
| `Error`     | Enrichment failed; inspect `context` for more information |
| `Skipped`   | Request was skipped; inspect `context` for the reason     |
| `Unknown`   | Status could not be recognised                            |

A typical integration flow is:

1. Submit a domain or email for enrichment.
2. Store the returned `requestId`.
3. Check the request status later.
4. Continue polling while the status is `Queued`.
5. When the status is `Completed`, retrieve the company from your Goodfit dataset.
6. For `Skipped` or `Error`, inspect `context`.

#### Lookup first, enrich second

Where you also use the Dataset API, check whether a company already exists before submitting it for enrichment.

```mermaid
flowchart LR
    A[Company enters workflow] --> B[Check Dataset API]
    B --> C{Company exists?}
    C -->|Yes| D[Use existing Goodfit record]
    C -->|No| E[Company Enrichment API]
    E --> F[Goodfit dataset]
```

This avoids submitting companies that are already present in your dataset.

#### Retrieve enriched data

The Company Enrichment API handles the enrichment request and its processing status.

The enriched company data itself is delivered into your **Goodfit dataset**, rather than being returned through the status endpoint.

Once a request is `Completed`:

1. Retrieve the company from the Dataset API.
2. Read the enriched company fields.
3. Use the data in your CRM, scoring, routing or other downstream workflow.

### Validation

Goodfit validates enrichment requests before accepting or processing them.

Domains are checked for:

* **Valid format** — the supplied value must be a valid domain.
* **Generic domains** — consumer email domains such as `gmail.com` cannot be enriched.

The same validation applies when the company domain is derived from an email address.

During processing, Goodfit may also inspect whether the domain can be loaded and where it redirects.

Where available, `context.domainCheck` may include:

* `domainLoads` — whether the domain could be successfully loaded.
* `loadedUrl` — the final URL reached, including redirects.

### Skipped requests

When an enrichment cannot be completed, the status may be `Skipped`.

The `context` object can contain additional information, including:

| Field                   | Description                                                |
| ----------------------- | ---------------------------------------------------------- |
| `skipReason`            | Machine-readable reason the request was skipped            |
| `skipReasonDescription` | Human-readable explanation of the skip reason              |
| `errorMessage`          | Description of an error encountered while processing       |
| `domainCheck`           | Information collected while validating the supplied domain |

`context` is `null` when there is no additional information to report.

#### Skip reasons

When a request is skipped, `context.skipReason` provides a machine-readable reason.

| Skip reason                 | Description                                                                        |
| --------------------------- | ---------------------------------------------------------------------------------- |
| `INVALID_DOMAIN`            | Domain is not a valid domain                                                       |
| `BLACKLISTED_DOMAIN`        | Domain is not eligible for enrichment, for example a personal email domain         |
| `DOMAIN_NOT_LOADABLE`       | Domain could not be reached or does not appear to be active                        |
| `DOMAIN_PARKED`             | Domain appears to be parked                                                        |
| `ID_RES_NO_COMPANY_ID`      | No matching company could be identified                                            |
| `ID_RES_NO_LINKEDIN_ID`     | No matching LinkedIn company could be identified from the domain                   |
| `SKIP_CREATE_CLIENT_DEST`   | Creating new client destinations is disabled and no existing destination was found |
| `LINKEDIN_NOT_ACTIVE`       | Matching LinkedIn company exists but is not active                                 |
| `ID_RES_NO_LINKEDIN_RECORD` | The identified LinkedIn company record was invalid                                 |

Your integration should treat `Skipped` as a finished request and use `context.skipReason` to decide what to do next.

### API reference

* [Enrich a company](https://docs.goodfit.io/goodfit-docs/apis/enrichment-api/company-endpoints#post-enrichment-enrich)
* [Check enrichment status](https://docs.goodfit.io/goodfit-docs/apis/enrichment-api/company-endpoints#get-enrichment-request-requestid)

For authentication, API keys, base URLs, rate limits and common API errors, see [API introduction](https://docs.goodfit.io/goodfit-docs/apis/apis-introduction).

For exact request and response schemas, field definitions and validation behaviour, refer to the API reference pages or OpenAPI specification.
