# US Business Licenses - 12 Local Registers (`j0401/us-business-licenses`) Actor

Business and occupational licences from twelve local registers — Chicago, Texas permits, Philadelphia, DC, Delaware, New Orleans, Cincinnati, Mesa, Norfolk, Berkeley, NYC DCWP and California counties. One schema; filter by name, licence, type, status, city or ZIP; monitor new licences.

- **URL**: https://apify.com/j0401/us-business-licenses.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / 1,000 us business licence records

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

## US Business Licenses - 12 Local Registers, One Schema

Business and occupational licence records from twelve local registers, server-side queryable, with a monitor mode for new licences.

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold.**

### What you get

- `jurisdiction`, `state`, `source` - which register the row came from
- `recordId`, `licenseNumber`
- `businessName`, `dbaName`, `ownerName`
- `licenseType`, `licenseCategory`
- `status` (normalised `active` / `inactive` / `unknown` where a status exists), `statusRaw`
- `startDate`, `eventDate` (the issuance / event date), `endDate`
- `address`, `city`, `stateCode`, `zip`, `naics`
- `sourceUrl`, `sourceUpdatedAt`

### Registers

| `jurisdiction` | Register | Notes |
|---|---|---|
| `chicago` (default) | Chicago business licences | current active licences only; one row per licence  business activity |
| `tx` | Texas sales-tax permit outlets | one row per outlet; current permits only |
| `philly` | Philadelphia business licences | rental and commercial in one table |
| `dc` | DC basic business licences | |
| `de` | Delaware business licences | |
| `nola` | New Orleans occupational licences | |
| `cincinnati` | Cincinnati business licences | |
| `mesa` | Mesa (AZ) business licences | |
| `norfolk` | Norfolk (VA) business licences | no licence id in the feed - `recordId` is derived |
| `berkeley` | Berkeley (CA) business licences | |
| `nyc` | NYC DCWP | `sub` picks licenses / applications / inspections / violations / complaints |
| `ca-county` | California counties | `sub` picks sac-fbn / sac-bl / sonoma |

### Modes

`mode=rows` (default) returns matching records.

`mode=aggregate` returns one count row per group (`groupBy`: licenseType, status, city, zip, licenseCategory), capped at `maxResults` groups (default 50 - raise it to get the long tail). A dimension the register does not publish is rejected; so is a group list the source would truncate. For `nyc` and `ca-county` the count is computed over the first 5,000 matching rows rather than a server-side group endpoint.

`mode=monitor` returns only records whose **event date** (issuance / filing date) is after your last run, and advances a per-user watermark in the actor's key-value store. The cursor is row-level: a page spanning several dates cannot skip the older ones. Owner runs do not advance the watermark unless `sinceLastRun=true`. Monitor is supported on the pushdown registers except `berkeley` (no date column), plus `nyc/licenses` and `ca-county`; the other NYC corpora have no issue-date axis and are rejected.

### Examples

```json
{ "jurisdiction": "chicago", "status": "AAI", "maxResults": 100 }
```

```json
{ "jurisdiction": "chicago", "issuedFrom": "2026-10-01", "maxResults": 100 }
```

```json
{ "jurisdiction": "tx", "city": "HOUSTON", "maxResults": 100 }
```

```json
{ "jurisdiction": "philly", "licenseType": "Rental", "maxResults": 100 }
```

```json
{ "jurisdiction": "dc", "name": "LLC", "maxResults": 100 }
```

```json
{ "jurisdiction": "nola", "owner": "SMITH", "maxResults": 100 }
```

```json
{ "jurisdiction": "philly", "owner": "SMITH", "maxResults": 100 }
```

```json
{ "jurisdiction": "norfolk", "name": "MARKET", "maxResults": 100 }
```

```json
{ "jurisdiction": "nyc", "sub": "licenses", "zip": "10001", "maxResults": 100 }
```

```json
{ "jurisdiction": "nyc", "sub": "applications", "status": "Submitted", "maxResults": 100 }
```

```json
{ "jurisdiction": "ca-county", "sub": "sac-fbn", "name": "CAFE", "maxResults": 100 }
```

```json
{ "jurisdiction": "mesa", "name": "CAFE", "maxResults": 100 }
```

```json
{ "mode": "monitor", "jurisdiction": "chicago", "maxResults": 100 }
```

```json
{ "mode": "aggregate", "jurisdiction": "chicago", "groupBy": "licenseType" }
```

### Honest limits

- **A row is a licence record, not a business.** Chicago publishes licence  activity rows; Texas publishes one row per outlet; Philadelphia mixes rental and commercial licences.
- **Filter availability differs by register.** Cincinnati's feed has no business-name column, so `name` is rejected there (use `licenseType`/`city`/`zip` or an id). Norfolk and Texas expose only a few grouping dimensions; `mode=aggregate` on a dimension the register does not publish is rejected rather than returning an empty or unfiltered answer. `licenseCategory` is a group dimension on NYC and the California counties only.
- **Several registers publish only current licences** (Chicago's current-active dataset, Texas, Delaware, New Orleans, Cincinnati) - Chicago still carries a status column; the others have none, so `status` stays blank there. **Blank is not "expired".**
- **Cincinnati publishes no business name at all** (the column exists but every row is empty; measured 2026-10-24). `businessName` is blank for that register - use the licence number and address.
- **Field availability is not uniform.** Berkeley publishes no licence type, status or issue date; DC and Mesa publish no ZIP; Norfolk publishes no city/ZIP/type/status. A filter the register cannot serve is rejected, not ignored.
- **Some dates are future.** Licence terms can start years ahead (DC has 2029-2034 start dates); `eventDate` is the term start / issue date as published. A 9999 sentinel is cleared. On the newest-first page those future starts can appear first.
- **Addresses can be sparse on the newest rows.** Philadelphia's newest licence rows frequently have no address/ZIP even though most of the corpus does; do not read a blank as "no address".
- **DC has no per-row freshness stamp**, so `sourceUpdatedAt` is blank there; the count floor still runs.
- `licenseType` is the local label, not a national taxonomy. The same trade can be named differently in two cities.
- **Norfolk has no licence number in its feed**; `recordId` is a stable hash of the name and address, so two records with the same name at the same address collapse to one id.
- **NYC `applications` states are not licence states.** `status` there is the application status (`Submitted`, `Pending`, ); `unknown` means the word is outside the normaliser's vocabulary, not that the application is invalid.
- **Monitor needs an issue-date axis.** The NYC applications/inspections/violations/complaints corpora have no single issue date and reject `issuedFrom`; use them with a date range of your own or the dedicated NYC actor.
- **PII**: these are public business registrations. Owner names are part of the record. Phone numbers and mailing addresses are never emitted (some sources return them in the raw payload; they are not mapped to the output).
- Filters a register cannot serve are rejected with a clear error - none are silently dropped.
- Every register has its own count floor; most also carry a freshness check. The California county family (`ca-county`) has a count floor but no freshness probe.

### Related

Also available in this account: **US contractor licenses** (nine state boards), **Chicago building permits**, **NYC ACRIS** and **NYC Tax Lien Sale Lists**.

# Actor input Schema

## `jurisdiction` (type: `string`):

chicago (default) / tx = Texas sales-tax permits / philly / dc / de / nola / cincinnati / mesa / norfolk / berkeley / nyc = NYC DCWP (choose a corpus with sub) / ca-county = Sacramento/Sonoma (choose with sub).

## `sub` (type: `string`):

nyc: licenses (default) / applications / inspections / violations / complaints. ca-county: sac-fbn (default) / sac-bl / sonoma. Must be blank for every other jurisdiction.

## `mode` (type: `string`):

rows = matching records. aggregate = one count row per group. monitor = only records issued after your last run (per-user watermark).

## `name` (type: `string`):

Substring match on the business name (owner name on Norfolk / ca-county where available).

## `licenseNumber` (type: `string`):

Exact licence / record number. Not available for NYC, ca-county or Norfolk (no such id in those feeds).

## `licenseType` (type: `string`):

The local licence label (substring). tx, norfolk and berkeley publish no licence type and reject it; for ca-county only sac-bl supports it (the licence activity).

## `status` (type: `string`):

The register's own status word (exact), e.g. AAI, Active, Expired, Filed. tx, de, nola, cincinnati, norfolk and berkeley publish no status and reject this filter - see the README.

## `city` (type: `string`):

Substring match. Available for chicago, tx, de, nola, cincinnati. Not for nyc/ca-county.

## `zip` (type: `string`):

Exact ZIP (NYC: the licence address ZIP; ca-county: prefix match). DC, Mesa and Norfolk publish no ZIP and reject this filter.

## `owner` (type: `string`):

Owner / principal name (Norfolk, Philadelphia, DC, New Orleans; ca-county sac-fbn and sonoma). Not available for NYC or ca-county sac-bl.

## `issuedFrom` (type: `string`):

ISO date. Only records issued on or after this date. Chicago uses date_issued; NYC supports it on the licenses corpus only. mode=monitor sets it from your watermark.

## `groupBy` (type: `string`):

mode=aggregate only (blank = licenseType). licenseCategory exists on NYC and ca-county/sac-bl only; other registers reject it.

## `sinceLastRun` (type: `boolean`):

Owner runs only: read and advance the monitor watermark. User runs in monitor mode always do.

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

Cap on records delivered (0 = default 50; up to 5,000 per run). In aggregate mode it caps the number of group rows. Each delivered record is metered individually.

## Actor input object example

```json
{
  "jurisdiction": "chicago",
  "sub": "",
  "mode": "rows",
  "groupBy": "",
  "sinceLastRun": false,
  "maxResults": 50
}
```

# Actor output Schema

## `recordsUrl` (type: `string`):

Business licence records - as JSON

## `datasetUrl` (type: `string`):

No description

## `runUrl` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("j0401/us-business-licenses").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("j0401/us-business-licenses").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 '{}' |
apify call j0401/us-business-licenses --silent --output-dataset

```

## MCP server setup

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

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/WYlCGGUDzqXeKTbeS/builds/9biTXgCkAdVNgxXe6/openapi.json
