# Iowa Business Entity Search - LLC, Corporation & Trade Name (`captainhandsome/ia-business-entity-search`) Actor

Search Iowa Secretary of State business records by name and get structured rows back: business number, name, status, name type and legal name. Matches LLCs, corporations and trade names. Submits the state's own search form, so no API key or scraping setup is needed.

- **URL**: https://apify.com/captainhandsome/ia-business-entity-search.md
- **Developed by:** [Joseph McRell](https://apify.com/captainhandsome) (community)
- **Categories:** Business, Other
- **Stats:** 2 total users, 1 monthly users, 25.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Iowa Business Entity Search Scraper

Search the Iowa Secretary of State business register by company name and get back the business number, the matched name, the entity's status, the name type and the registered legal name as structured records. You give it a name, not a URL: Iowa's registry has no shareable results link, so this Actor fills in and submits the public search form for you. No API key, no login, no captcha. Set `max_items` before each run and the cost of the run is decided before it starts.

### What data can I extract?

- The Iowa business number, which is the key for looking an entity up on the state site
- Every name the register holds against that entity: legal names, fictitious (trade) names and former names
- The entity's registry status, so you can drop dead companies before they reach a call list
- The registered legal name behind a trade name, which is what turns "a-1 locksmith" into "a1 all american locksmith llc"

Five fields per row, one row per matching name. Values are Unicode-normalised, whitespace-collapsed and lowercased, so they are safe to dedupe and join against other datasets without a cleaning pass. Everything lands in the default dataset and downloads as JSON, CSV, Excel or XML.

One thing to know before your first run: **Iowa matches anywhere in the name, not just at the start.** Searching `SMITH` also returns `10 minute locksmith llc` and `4r gunsmithing, l.lc.`. That is the state's own search behaviour, not a defect here. It is useful for broad sweeps and misleading if you assume a prefix match.

#### All 17 columns

**Identity** — `business_number`, `legal_name`, `name`

**Status** — `state_of_inc`, `status`, `type`

**Dates** — `effective_date`, `expiration_date`, `filing_date`

**Location** — `principal_address`, `principal_address_2`, `principal_city_state_zip`, `registered_agent_address`, `registered_agent_address_2`, `registered_agent_city_state_zip`

**People** — `registered_agent`

**Other detail** — `chapter`

### Input example

```json
{
  "search_terms": ["SMITH"],
  "max_items": 25
}
```

`search_terms` takes a list, so one run can cover several names. `max_items` is a hard ceiling on records emitted and therefore on what the run can cost; it defaults to 100. `start_urls` exists in the shared input schema for registries that have GET-able result pages — Iowa does not, so leave it empty and use `search_terms`.

### Output example

Real records from a run of the input above:

```json
[
  {
    "business_number": "853463",
    "name": "10 minute locksmith llc",
    "status": "active",
    "type": "legal",
    "legal_name": "10 minute locksmith llc"
  },
  {
    "business_number": "748031",
    "name": "a-1 locksmith",
    "status": "active",
    "type": "fictitious name",
    "legal_name": "a1 all american locksmith llc"
  },
  {
    "business_number": "2488",
    "name": "a-1 locksmith services, inc.",
    "status": "active",
    "type": "former",
    "legal_name": "flatlander forge, inc."
  },
  {
    "business_number": "37810",
    "name": "a. & c. smith farm, ltd.",
    "status": "inactive",
    "type": "legal",
    "legal_name": "a. & c. smith farm, ltd."
  }
]
```

Read `type` as "what kind of name is in the `name` column", not "what kind of company this is". On `legal` rows `name` and `legal_name` are the same string. On `fictitious name` and `former` rows they differ, and the pair is the useful part: a trade name on the left, the company that actually owns it on the right. `business_number` repeats across rows when one entity holds several names — 748031 above appears three times in the same run: once as its legal name and once for each of the two trade names registered against it.

### Common use cases

- **Lead lists for local services.** Sweep a trade word ("locksmith", "plumbing", "roofing") and keep the `active` rows. The contains-match that surprises people on a name search is exactly what you want here.
- **Trade name resolution.** You have a name from an invoice, a sign or an ad and need the registered company behind it. Search the trade name, read `legal_name`.
- **Vendor and counterparty checks.** Confirm an Iowa counterparty exists in the register and is not `inactive` before onboarding them.
- **Deduplicating a CRM.** The normalised output joins cleanly against existing records, and `business_number` gives you a stable key that survives rebrands.
- **Chasing a rename.** A `former` row points from an old name to the current legal name, which is how you find a company that has moved on since your data was collected.

### Use with AI agents and MCP

Apify's MCP server can discover and call this Actor from an agent workflow. A workable intent:

> Search the Iowa business register for "locksmith", return at most 25 records, and give me the active ones with their legal names.

Pass the JSON from **Input example** as the tool arguments. The input schema is strict and rejects unsupported parameters rather than silently ignoring them, and each dataset field carries a title, a description and a real example, so an agent can interpret `type` and `legal_name` without guessing. Point the agent at `max_items` as its spend control: it is the only lever that bounds the record count, and the agent should set it explicitly rather than inherit the default.

### Pricing and cost control

Output is billed per result at **$0.004 per result** (about $4.00 per 1,000 results), plus a $0.0005 Actor-start charge billed once per gigabyte of memory at run start. Use `max_items` to cap both output volume and charges. The price shown on the Apify Store listing is authoritative.

There is no subscription and no minimum. You are not billed for the platform compute time the run consumes — this Actor makes no browser request, only plain HTTP, so a run is cheap to execute and that cost sits with the developer, not you.

`max_items` is the ceiling. Set it to 10 for a first look, read what comes back, then scale once you know the search term behaves as you expect. A vague term on a contains-match registry is the one way to spend more than you meant to.

### Reliability

The extraction selectors are not hard-coded into a build. They live in an environment variable that an automated monitor re-derives from the live site every night, validating each candidate against two independent searches and a schema contract before it ships, so ordinary layout drift is usually repaired before a buyer sees it. A run against the bounded default input is kept as a canary.

The Iowa site is ASP.NET, which means the search form only accepts a POST carrying a matching hidden-field pair from a freshly fetched page. This Actor fetches the form first and echoes those fields back on every term, which is what makes the registry reachable over plain HTTP at all. If the state site is down or rate-limiting, the run fails loudly with the HTTP status rather than writing an empty dataset and reporting success.

### Limitations and responsible use

- **Five fields only.** Registered agents, officers, addresses and filing dates live on each entity's detail page and would need a further request per record. This Actor does not open detail pages.
- **First results page per term.** There is no pagination. A very common term returns the first page the state serves and stops; narrow the term rather than raising `max_items`.
- **Name search only.** You cannot search by business number, agent or address.
- **Iowa only.** Other states run different systems and are covered by separate Actors.
- **Status vocabulary is thin.** Live output shows `active` and `inactive`. There is no dissolution date, no good-standing flag and no filing history in this table.
- **Case is lost.** Output is lowercased by design for matching. If you need display-cased names, title-case them downstream or fetch the detail page.

Iowa corporate registrations are public records published by the Iowa Secretary of State, and this Actor submits the same public form a visitor would. It collects nothing behind a login. How you use the results is on you, including any marketing, screening and data-protection rules that apply to your use.

### FAQ

#### Why does searching SMITH return locksmiths?

Because Iowa's own search matches the term anywhere in the name. It is the source's behaviour, faithfully passed through. Use a longer or more distinctive term if you want fewer incidental hits.

#### Do I need an API key or an Iowa account?

No. The register is public and this Actor needs no credentials of any kind.

#### Why do two rows share a business number?

One entity can hold several names — its legal name plus any fictitious names it has registered. Each name is a row; the business number identifies the entity they all belong to. Deduplicate on `business_number` if you want one row per company.

#### What does `type: former` mean?

The name matched is one the entity used previously. `legal_name` on that row is the name it goes by now.

#### Can I get addresses, officers or filing dates?

Not from this Actor. Those fields are on the per-entity detail page, which this Actor does not open.

#### How do I control what a run costs?

Set `max_items`. It caps the number of records emitted, and records are what you are charged for. Start at 10.

#### Can I export the results?

Yes. Download the dataset as JSON, CSV, Excel or XML from the run's Dataset tab, or pull it from the Apify API.

#### What happens if a field is missing on the source page?

That field comes back as `null` for that record only. A missing value never shifts the other fields or the rows that follow it.

# Changelog

This Actor's version history is a separate document: https://apify.com/captainhandsome/ia-business-entity-search/changelog.md

# Actor input Schema

## `start_urls` (type: `array`):

Result pages to extract from. Used by targets with GET-able result URLs. Supply these OR Search terms.

## `max_items` (type: `integer`):

Hard cap on emitted records (also caps the user's PPE spend).

## `search_terms` (type: `array`):

Names to search for. Used by search-form targets that have no GET-able results URL. Supply these OR Start URLs.

## Actor input object example

```json
{
  "max_items": 100,
  "search_terms": [
    "SMITH"
  ]
}
```

# Actor output Schema

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

Extracted records, one object per row on the source page.

# 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 = {
    "search_terms": [
        "SMITH"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("captainhandsome/ia-business-entity-search").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 = { "search_terms": ["SMITH"] }

# Run the Actor and wait for it to finish
run = client.actor("captainhandsome/ia-business-entity-search").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 '{
  "search_terms": [
    "SMITH"
  ]
}' |
apify call captainhandsome/ia-business-entity-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,captainhandsome/ia-business-entity-search"
        }
    }
}
```

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/rFARtAKjs6o5IRbFg/builds/StMAAyVIW2aLQTvEV/openapi.json
