# Firmographic Append API - Company Data Enrichment by Domain (`nabeelbaghoor/firmographic-append-api`) Actor

Append firmographic data to domains, business emails and company records: industry, NAICS and SIC codes, employee count, sales volume, year founded, address and phone. Also resolves IP addresses and hashed emails to business domains. Pay per result. Bring your own API key.

- **URL**: https://apify.com/nabeelbaghoor/firmographic-append-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Business, Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$12.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Firmographic Append API - Company Data Enrichment by Domain

Turn a list of domains, business emails, company records, IP addresses, hashed emails or LinkedIn profiles into structured company records: industry, NAICS and SIC codes with descriptions, employee count, sales volume, year founded, postal address, phone and website, one flat row per match.

### What this actor does

- **Appends firmographics to a domain or a business email**, the way you enrich a CRM export, a signup list or a form fill that only captured a work address.
- **Appends firmographics to a company name plus address or phone**, for the records that never had a domain in the first place.
- **Resolves IP addresses to business domains**, returning up to three domains per address with the firmographics for each. This is how anonymous website traffic becomes a named account list.
- **Resolves hashed emails to business domains**, so privacy hashed source data can still be enriched. MD5, SHA1 and SHA256 are supported in upper, lower and natural case.
- **Resolves people to their employer**, returning job title, seniority, department, business email and the company's firmographics from a LinkedIn URL, a name or a personal email.
- **Filters matches server side.** A required field value, for example `Country=US`, drops non-matching records before they are returned, so they never reach the dataset and are never charged for.
- **Keeps every field the API returns** and layers stable normalized columns on top, so one dataset holds rows from all five lookup types with the same header names.
- **Records misses instead of hiding them.** An input with no match becomes a row with `matched: false`, so a list with dead domains still finishes and you can see exactly which inputs resolved.
- **Never charges for a miss.** Only rows carrying an actual match record are billed.

### Input

| Field | What it does |
| --- | --- |
| `domains` | Company domains to append firmographics to. A pasted URL is reduced to the bare hostname. |
| `businessEmails` | Business email addresses to append firmographics to. |
| `companyRecords` | JSON records using `business`, `address`, `city`, `state`, `zip`, `phone`, for lookups by name. |
| `ipAddresses` | IPv4 addresses to resolve to business domains. |
| `hashedEmails` | MD5, SHA1 or SHA256 hashed emails to resolve to a business domain. |
| `linkedinUrls` | LinkedIn profile URLs to resolve to a person's employer and role. |
| `personRecords` | JSON records using `first`, `last`, `email`, `domain`, `linkedin_url`. |
| `requireValues` | Server side filters, one `Field Name=Value` rule per line. |
| `skipUnmatched` | Leave unresolved inputs out of the dataset. |
| `maxRequestSeconds` | Cap how long the API may spend on a single lookup. |
| `maxResults` | Hard cap on rows, and therefore on spend and run time. |
| `apiKey` | Your own API key, sent as a header. Stored as a secret. |

### Example output

```json
{
  "recordType": "firmographic",
  "matched": true,
  "query": "example.com",
  "businessName": "Example Labs Inc",
  "domain": "example.com",
  "website": "https://www.example.com",
  "phone": "8005550142",
  "address": "500 Market St",
  "city": "Redmond",
  "state": "WA",
  "zip": "98052",
  "country": "US",
  "industry": "Computer Software",
  "naicsCode": "541511",
  "naicsDescription": "Custom Computer Programming Services",
  "sicCode": "7372",
  "sicDescription": "Prepackaged Software",
  "employees": "320",
  "salesVolume": "48000000",
  "yearFounded": "2011",
  "ownership": "Private",
  "queryId": "b2f1c0d4-8a91-4d2e-9f0a-1c7b5e2d3a44",
  "raw": { }
}
```

### Frequently asked questions

#### What data does the Firmographic Append API return?

Each match carries the standardized business name, postal address, city, state, ZIP and country, the business phone, the company domain and website home page, the industry with its NAICS and SIC codes and descriptions, the employee count, the sales volume, the year founded, and whether the business is public or private. Person lookups additionally return job title, seniority, department, business email and LinkedIn profile URL alongside the employer's firmographics.

#### Do I need my own API key?

Yes. This actor does not include data access. You use your own API key from Versium, which is the provider whose REACH API this actor calls, created on their developer portal. Your own plan, match allowance and terms apply. Paste the key into the `apiKey` field, where it is stored as an Apify secret and sent as a request header rather than a URL parameter, so it never appears in a log line or a redirect.

#### What inputs does a firmographic lookup need?

One of four documented combinations: a business email on its own, a company domain on its own, a business name with address, city and state, or a business name with a phone number. Anything less cannot be matched. The actor checks each record against those combinations before it sends anything, so an incomplete record is reported in the dataset and costs you no request.

#### How do I turn website visitors into company records?

Feed the visitor IP addresses into `ipAddresses`. Each IPv4 address resolves to up to three business domains, and every domain comes back with full firmographics attached, so a raw server log becomes an account list in one run. Residential and mobile addresses often resolve to nothing, which is expected and shows up as a `matched: false` row.

#### Can I enrich data that has already been hashed for privacy?

Yes. Put the hashes into `hashedEmails`. MD5, SHA1 and SHA256 are supported in upper, lower and natural case, and each hash resolves to the associated business domain without the plain address ever leaving your systems.

#### How do I only keep records from one country or industry?

Add a rule to `requireValues` in the form `Field Name=Value`, for example `Country=US`. The filter is applied by the API before results are returned, so non-matching records never reach your dataset and are never billed. Add more lines to require more fields at once.

#### What happens when an input has no match?

The row is written with `matched: false` and an `error` explaining the miss, and the run continues to the next input. Misses are not charged for. Set `skipUnmatched` to true to leave them out of the dataset entirely.

#### How much does a run cost?

Pricing is pay per result: you are charged for each match record returned to the dataset, and never for misses, rejected records or duplicates. Apify platform usage is included in the per-result price. Your own API provider's match allowance is separate and billed by them.

#### How many requests does a run make?

One per input, because every data tool here is one record per request. A 500 domain list is 500 requests. The provider documents a limit of 20 queries per second and the actor paces itself well under that, backing off on HTTP 429, so a large list finishes rather than tripping the limiter halfway through.

### Keyword map

firmographic append API, company data enrichment, B2B data append, domain to company data, email to company lookup, IP to company API, IP to domain, website visitor identification, hashed email enrichment, HEM to domain, NAICS code lookup, SIC code lookup, employee count data, company revenue data, CRM enrichment API, lead enrichment API, account based marketing data, person to company match

# Actor input Schema

## `domains` (type: `array`):

Company domains to append firmographics to, one per line. A full URL works too: it is reduced to the bare hostname before the request. A domain on its own is a complete lookup.

## `businessEmails` (type: `array`):

Business email addresses to append firmographics to, one per line. A business email on its own is a complete lookup. Consumer mailbox addresses will not resolve to a company.

## `companyRecords` (type: `string`):

Company records to look up when you have a name rather than a domain. Paste a JSON array of objects, or one JSON object per line, using the field names business, address, city, state, zip and phone. Each record must satisfy a documented minimum combination: business plus address, city and state, or business plus phone. Records that do not are reported in the dataset and never cost a request.

## `ipAddresses` (type: `array`):

IPv4 addresses to resolve to business domains, one per line. Each address returns up to three domains with the firmographics for each, which is how you turn anonymous website traffic into named accounts.

## `hashedEmails` (type: `array`):

Hashed email addresses to resolve to a business domain, one per line. MD5, SHA1 and SHA256 are supported in upper, lower and natural case. Use this when your source data is privacy hashed and you cannot send the plain address.

## `linkedinUrls` (type: `array`):

LinkedIn profile URLs of people, one per line. Each returns that person's job title, seniority, department, business email and the firmographics of the company they work for.

## `personRecords` (type: `string`):

People to resolve to their employer when you have a name or a personal email rather than a LinkedIn URL. Paste a JSON array of objects, or one JSON object per line, using the field names first, last, email, domain and linkedin\_url, for example {"first": "Jane", "last": "Doe", "email": "jane@example.com"}. Each record needs a first and last name, an email, or a LinkedIn URL.

## `requireValues` (type: `array`):

Filter matches server side by requiring a field to hold an exact value. One rule per line in the form Field Name=Value, for example Country=US. Records that do not match are not returned and are not charged for.

## `skipUnmatched` (type: `boolean`):

Leave inputs that returned no match out of the dataset. Off by default, because keeping the misses is what lets you see which inputs resolved. Unmatched rows are never charged for either way.

## `maxRequestSeconds` (type: `integer`):

Cap how long the API may spend on a single lookup before it gives up and returns what it has. Leave empty to use the provider's own default. Lowering it makes a large list finish faster at the cost of a few deeper matches.

## `maxResults` (type: `integer`):

Stop after this many rows. Every lookup costs one request, so this is the cap on both spend and run time.

## `apiKey` (type: `string`):

Your own B2B data API key, sent as a request header. Required for every lookup. Stored as a secret, so it never appears in a log line or a URL.

## Actor input object example

```json
{
  "domains": [
    "stripe.com",
    "figma.com"
  ],
  "companyRecords": "[{\"business\": \"Versium\", \"address\": \"7530 164th AVE NE\", \"city\": \"Redmond\", \"state\": \"WA\", \"zip\": \"98052\"}]",
  "skipUnmatched": false,
  "maxResults": 100
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "domains": [
        "stripe.com",
        "figma.com"
    ],
    "companyRecords": "[{\"business\": \"Versium\", \"address\": \"7530 164th AVE NE\", \"city\": \"Redmond\", \"state\": \"WA\", \"zip\": \"98052\"}]"
};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/firmographic-append-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "domains": [
        "stripe.com",
        "figma.com",
    ],
    "companyRecords": "[{\"business\": \"Versium\", \"address\": \"7530 164th AVE NE\", \"city\": \"Redmond\", \"state\": \"WA\", \"zip\": \"98052\"}]",
}

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/firmographic-append-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "domains": [
    "stripe.com",
    "figma.com"
  ],
  "companyRecords": "[{\\"business\\": \\"Versium\\", \\"address\\": \\"7530 164th AVE NE\\", \\"city\\": \\"Redmond\\", \\"state\\": \\"WA\\", \\"zip\\": \\"98052\\"}]"
}' |
apify call nabeelbaghoor/firmographic-append-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/firmographic-append-api"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/xfVQRR9biKpCZjklL/builds/l5y6a1kJTg4e0VcoK/openapi.json
