# US Business Verify (`sourcewire/us-business-verify`) Actor

Verify US businesses for AI agents: state registry status (TX, NY, CO, CT, OR) plus OFAC and US export-list sanctions screening. Fail-closed PASS / REVIEW / FAIL / INCOMPLETE verdict with cited sources and timestamps.

- **URL**: https://apify.com/sourcewire/us-business-verify.md
- **Developed by:** [Curtis Still](https://apify.com/sourcewire) (community)
- **Categories:** Developer tools, AI, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 business reports

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## US Business Verify — registry status + sanctions screening for AI agents

Check whether a US business exists and is active in its official state registry, and screen it against the OFAC
sanctions lists and US export screening lists. You get one fail-closed verdict per business:
**PASS / REVIEW / FAIL / INCOMPLETE**. Every verdict comes with reason codes, match confidence, and a source URL and
retrieval timestamp for every finding. The output is compact JSON that an agent can act on directly.

### Why use it

- **One verdict instead of five government websites.** Registry status, sanctions, and export lists are checked in one call.
- **Fail-closed.** If a source is down, stale, or not covered, you get INCOMPLETE. You never get a false PASS.
- **Cited.** Every finding names its official source, the URL, when it was retrieved, and when the source data was last updated.
- **Fair billing.** You pay only for businesses that were actually found and given a definitive verdict. INCOMPLETE and not-found results are free.

### Use cases

- KYB / vendor onboarding: confirm that a supplier, customer, or counterparty is a registered, active entity and not sanctioned.
- AI agents and MCP: give an agent a `verify_business` tool that returns a verdict instead of a web page.
- Bulk list hygiene: re-check a vendor list and flag dissolved entities or sanctions matches.

### What it checks

| Check | Default | Source (official, public) | Notes |
|---|---|---|---|
| `registry`: existence and status | on | State open-data portals: **TX** Comptroller Active Franchise Taxpayers, **NY** Department of State Active Corporations plus Name History and Status History, **CO** Secretary of State Business Entities, **CT** Business Registry, **OR** Secretary of State Active Businesses | CO, CT, and NY confirm inactive entities (dissolved, inactive, and so on). TX and OR publish active entities only, so a business missing from them is REVIEW, not FAIL. |
| `sanctions` | on | OFAC SDN and Consolidated (non-SDN) lists, including aliases and listed addresses, plus the US Consolidated Screening List (BIS Entity List, Denied Persons, Unverified, MEU, ITAR debarred, nonproliferation) | Business and other non-individual entries only. Downloaded fresh on every run. |
| `exclusions` | **off (opt-in)** | SAM.gov Exclusions API | Requires **your own** SAM.gov API key (`samApiKey`). If you request it and the key is missing or rejected, the result is INCOMPLETE. |

**A PASS covers only the checks that ran.** Each result lists `checksRun` and `checksNotRun`, and includes a
plain-language `verdictScope`. With the default settings, a PASS means "registry + sanctions passed". It says
nothing about SAM.gov exclusions.

#### Supported states

| State | Status |
|---|---|
| TX, NY, CO, CT, OR | Supported, live data |
| FL | **Not available on this Actor: always INCOMPLETE (not charged).** Florida publishes its corporate data only as bulk files on its own file-transfer portal. This Actor does not have a provisioned index of those files. |
| DE | **Always INCOMPLETE (not charged).** Delaware has no free bulk file or API. Its entity search is CAPTCHA-protected and its terms prohibit automated access. The Actor never contacts Delaware's site. |
| Any other state | INCOMPLETE (`STATE_NOT_COVERED`, not charged) |

If you leave out `state`, the Actor searches TX, NY, CO, CT, and OR, and lists the states it did not search in
`registry.statesNotSearched`.

### The four verdicts

- **PASS**: every check that ran finished on fresh data, and every one of them passed.
- **REVIEW**: a person should decide. Examples: several active entities share the name; the match has low confidence or a different legal suffix; the entity was not found; it is not in good standing; it is missing from an active-only list; or it has a **sanctions name match with no second identifier**.
- **FAIL**: a confirmed disqualifying fact. Examples: the entity is dissolved, inactive, revoked, forfeited, or merged out; a sanctions or export-list match is **corroborated** by an ID, address, or country; or an active SAM.gov exclusion exists.
- **INCOMPLETE**: a requested check could not finish. Causes include a source error, a timeout, stale data, a missing key, or a state that is not covered or is restricted. **Never PASS. Never charged.**

FAIL takes precedence over INCOMPLETE, because a confirmed bad fact stands even if another check failed.

#### Sanctions: name match vs corroborated match

A name match alone (exact, alias, or strong) is **REVIEW** (`SANCTIONS_NAME_MATCH`). It becomes **FAIL**
(`SANCTIONS_MATCH_CORROBORATED`) only when an exact or strong name match is backed by strong evidence:

- an ID you supply (`taxId`, `ein`, `registrationNumber`, `lei`, `duns`, `swift`) that equals an ID on the list entry;
- a listed address in the subject's country that shares the postal code, the street, or, when `country` is given, the city;
- for an exact name match only, an explicit `country` that equals a listed address country.

A US state alone never corroborates. Fuzzy (`POSSIBLE`) matches are never FAIL; any matching evidence is shown so
a person can escalate. Before acting on any sanctions result, confirm it with the issuing agency.

### Input

```json
{
  "businesses": [
    {"name": "Chipotle Mexican Grill, Inc.", "state": "CO"},
    {"name": "Etsy, Inc.", "state": "NY"},
    {"name": "Acme Trading Ltd", "country": "Spain", "address": "Avenida Example 8", "city": "Madrid"}
  ],
  "checks": ["registry", "sanctions"]
}
```

Item fields: `name` (required unless `entityId` is given), `state` (two letters, strongly recommended), and the
optional `entityId`, `city`, `zip`, `address`, `country`, `taxId`, `ein`, `registrationNumber`, `lei`, `duns`, and
`swift`. Other inputs:

- `names` plus `defaultState`: a quick list of names.
- `checks`: choose from `registry`, `sanctions`, and `exclusions`.
- `samApiKey`: a secret, needed only for exclusions.
- `includeExportScreening`: default true.
- `maxSourceAgeHours`: freshness override.
- `maxBusinesses`: default 100.

### Output (one dataset item per business)

```json
{
  "name": "Etsy Payments, Inc.",
  "state": "NY",
  "verdict": "FAIL",
  "reasonCodes": ["ENTITY_INACTIVE"],
  "checksRun": ["registry", "sanctions"],
  "checksNotRun": ["exclusions"],
  "verdictScope": "The verdict covers only these checks: registry, sanctions. Not run (not covered by this verdict): exclusions.",
  "registry": {"matchedEntity": {"entityId": "3953312", "name": "ETSY PAYMENTS, INC.", "status": "INACTIVE",
               "statusRaw": "NY DOS status history: latest status 'Inactive' (filed 2011-12-13, ...)",
               "matchLabel": "EXACT", "matchConfidence": 1.0}},
  "findings": [{"code": "ENTITY_INACTIVE", "check": "registry", "outcome": "FAIL", "message": "...",
                "url": "https://data.ny.gov/resource/3gg2-jgnp.json", "retrievedAt": "2026-10-29T23:52:13Z",
                "sourceDataUpdatedAt": "2026-10-29T12:35:45Z"}],
  "citations": [{"source": "NY Department of State - Entity Status History", "url": "...", "retrievedAt": "..."}],
  "found": true,
  "billable": true,
  "checkedAt": "2026-10-29T23:52:13Z",
  "disclaimer": "..."
}
```

Also included where they apply: `registry.perState[]` (requests, data freshness, candidates), `sanctions.hits[]`
(list, programs, listed countries, corroboration evidence), `exclusions`, and `checksIncomplete`.

### For AI agents

- **MCP:** add `https://mcp.apify.com/?tools=sourcewire/us-business-verify` to your MCP client (Claude Desktop,
  Cursor, and others), or call the Actor through the Apify API.
- Read `verdict` first, then `verdictScope`, `reasonCodes`, and `findings[].message`. Treat REVIEW as "ask a
  human". Treat INCOMPLETE as "unknown; retry later or check manually". Never treat INCOMPLETE as PASS.
- Pass `state` whenever you know it. Pass `country`, `address`, and IDs when you have them, so sanctions matches
  can be corroborated or cleared.

### Pricing

Pay per event: **$0.008 per business report**. You are charged only for PASS, REVIEW, or FAIL results where the
business was found (a registry match or a corroborated list hit). INCOMPLETE and not-found results are never
charged. The standard Apify platform events also apply (Actor start and dataset result, a fraction of a cent).
Retried or resumed runs never charge the same business twice.

### Limitations

- Registry coverage is TX, NY, CO, CT, and OR. FL and DE return INCOMPLETE (see above).
- The TX source is the Comptroller's franchise-tax roll, so entities not subject to franchise tax may be absent from it.
- TX and OR publish active entities only, so the Actor cannot confirm inactivity there.
- Name matching is heuristic. `EXACT` and `STRONG` (legal suffix missing on one side) count as confirmed; a suffix
  mismatch or a fuzzy match is REVIEW only. Add `entityId`, `city`, or `zip` to resolve ambiguity.

### Disclaimer

This Actor runs automated lookups of public government data. Its results are not an official determination and
not legal advice. It covers **business entities only**. **It is not a consumer report** as defined by the Fair
Credit Reporting Act (FCRA). Do not use it for any FCRA purpose, such as decisions about credit, employment,
insurance, or housing for individuals.

### Development

```
python -m venv .venv && .venv/bin/pip install httpx pytest
.venv/bin/python -m pytest -q
.venv/bin/python -m src.cli smoke/smoke_input_v02.json out.json
```

# Actor input Schema

## `businesses` (type: `array`):

Businesses to verify. Each item: {"name": "Acme Widgets LLC", "state": "CO", "entityId": "optional state ID", "city": "optional", "zip": "optional", "address": "optional street", "country": "optional (name or ISO2)", "taxId"/"ein"/"registrationNumber"/"lei"/"duns"/"swift": "optional IDs"}. Supplying the state is strongly recommended; without it all automatable states are searched. Address/country/ID fields are used to corroborate sanctions name matches.

## `names` (type: `array`):

Shortcut: plain business names; uses Default state.

## `defaultState` (type: `string`):

Two-letter state used for items without a state. Covered: TX, NY, CO, CT, OR, FL (needs a provisioned local Sunbiz index, else INCOMPLETE), DE (always INCOMPLETE: no automatable free source).

## `checks` (type: `array`):

Which checks to run. Default: registry + sanctions. 'exclusions' (SAM.gov) is opt-in and needs your own SAM.gov API key. The verdict covers only the checks that ran (listed in each result as checksRun / checksNotRun). A requested check that cannot complete makes the verdict INCOMPLETE, never PASS.

## `samApiKey` (type: `string`):

Your own SAM.gov public API key, needed only if you add 'exclusions' to Checks (free key: SAM.gov > Account Details). Stored as a secret and redacted from output. If exclusions is requested without a working key, results are INCOMPLETE.

## `includeExportScreening` (type: `boolean`):

Also screen the Commerce/State lists in the trade.gov Consolidated Screening List (Entity List, Denied Persons, Unverified, MEU, ITAR debarred, nonproliferation).

## `maxSourceAgeHours` (type: `integer`):

Override the per-state freshness limit. Data older than this makes the registry check INCOMPLETE. Defaults: NY/CO/CT 96 h (NY status history 240 h), OR 336 h, TX 840 h, FL local index 192 h.

## `maxBusinesses` (type: `integer`):

Maximum number of businesses processed in one run (extra items are ignored).

## Actor input object example

```json
{
  "businesses": [
    {
      "name": "Chipotle Mexican Grill, Inc.",
      "state": "CO"
    },
    {
      "name": "Etsy, Inc.",
      "state": "NY"
    }
  ],
  "checks": [
    "registry",
    "sanctions"
  ],
  "includeExportScreening": true,
  "maxBusinesses": 100
}
```

# Actor output Schema

## `results` (type: `string`):

All business records in the default dataset (Verdicts view selected).

# 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 = {
    "businesses": [
        {
            "name": "Chipotle Mexican Grill, Inc.",
            "state": "CO"
        },
        {
            "name": "Etsy, Inc.",
            "state": "NY"
        }
    ],
    "checks": [
        "registry",
        "sanctions"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sourcewire/us-business-verify").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 = {
    "businesses": [
        {
            "name": "Chipotle Mexican Grill, Inc.",
            "state": "CO",
        },
        {
            "name": "Etsy, Inc.",
            "state": "NY",
        },
    ],
    "checks": [
        "registry",
        "sanctions",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("sourcewire/us-business-verify").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 '{
  "businesses": [
    {
      "name": "Chipotle Mexican Grill, Inc.",
      "state": "CO"
    },
    {
      "name": "Etsy, Inc.",
      "state": "NY"
    }
  ],
  "checks": [
    "registry",
    "sanctions"
  ]
}' |
apify call sourcewire/us-business-verify --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sourcewire/us-business-verify"
        }
    }
}
```

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/A370K2QYv9gK9T7LF/builds/o8q2kSbWP122MdTGI/openapi.json
