# New Jersey Professional Licenses - DCA Licensee Register (`j0401/nj-professional-licenses`) Actor

New Jersey Division of Consumer Affairs license register (1.99M rows, free public data): every licensed professional and facility - nurses, doctors, contractors - with license number, type, status, dates, address, county and discipline. Search by name, number, city, type or status.

- **URL**: https://apify.com/j0401/nj-professional-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 new jersey professional license 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

## New Jersey Professional Licenses - DCA Licensee Register

The New Jersey Division of Consumer Affairs publishes its **entire register of professional and occupational licensees** as free public files - no login, no key. This actor turns that whole register into a **charged-per-record lookup and screening tool**.

**Built for:** license verification and credentialing - checking whether a nurse, doctor, contractor, accountant or pharmacy is licensed and in good standing; screening suspensions and revocations; facility and vendor due diligence; workforce and market analysis by profession, county or city; and building licensed-entity lists for outreach.

### What it covers

**1,986,888 license records** - **1,854,331** individual-license and **132,557** facility-license rows (**a licensee may hold more than one**) - across the state's regulating boards:

| Board / profession | Records |
|---|---|
| Nursing | 762,466 |
| Cosmetology and Hairstyling | 327,523 |
| Medical Examiners | 154,522 |
| Pharmacy | 125,781 |
| Dentistry | 88,852 |
| Engineers & Land Surveyors | 63,421 |
| Social Work Examiners | 57,330 |
| Accountancy | 56,971 |
| Electrical Contractors | 46,456 |
| Home Improvement Contractors | 26,120 |

and 39 more boards and professions.

Every record carries the **license number**, the **license/credential type**, the **regulating board**, the **status**, the **issue, expiration and last-renewal dates**, how the license was obtained, the licensee's **name** (a person's full name, or a facility's business name), the **mailing address, city, state, ZIP and county**, and the register's own **discipline flag**.

> **Two things worth knowing.** The register is the **whole database**, not just current licensees: **834,133** licenses are **Active**, **815,941** are **Expired**, **246,354** **Inactive**, and the rest run to Out of Business, Deceased, Revoked, Suspended, Retired and more - so a name check sees the full history, not only today's actives. And **35,825 records carry a discipline flag** (the register's own marker for licensees with discipline on file) - a screening facet a plain license list does not carry.

### Typical questions

- "Is **this licensee** (by name or license number) licensed in New Jersey, and in what status?"
- "Show every **active registered nurse in Bergen County**."
- "Is **this contractor** in the register - and does it carry a **discipline** flag?"
- "Which **medical doctors** were **suspended** or **revoked**?"
- "How are New Jersey licenses **distributed by profession, county and city**?"

### Inputs

| Input | What it does |
|---|---|
| `licenseNumber` | exact license number -> that record(s) |
| `name` / `lastName` | licensee full name or business name / last name, substring, case-insensitive |
| `city` / `county` / `zipCode` | licensee location |
| `licenseType` / `profession` | credential type / regulating board, substring |
| `status` / `entityType` | exact status / `individual` or `facility` |
| `statusActive` / `hasDiscipline` | active licenses only / licensees carrying a discipline flag |
| `expirationFrom` / `expirationTo` | license expiration-date window (`YYYY`, `YYYY-MM` or `YYYY-MM-DD`) |
| `aggregate` / `groupBy` | one summary row per group with a count - profession / entity type / status / county / city |
| `maxResults` | cap records. The `aggregate` mode returns every group in full and is **not** cut by this cap. |

**Default run = a tiny aggregate** (the profession mix) - fast and safe for the daily auto-test, never a surprise full dump. For records, add a `name` / `city` / `licenseType` filter or a `licenseNumber`.

### Example inputs

**Look up one license** - a bare license number returns the matching record(s).

```json
{ "licenseNumber": "25MA00045800" }
```

**Active registered nurses in Bergen County** -

```json
{ "licenseType": "Reg. Prof. Nurse", "county": "Bergen", "statusActive": true, "maxResults": 10 }
```

**Licensees carrying a discipline flag** -

```json
{ "hasDiscipline": true, "maxResults": 10 }
```

**The profession mix** - one summary row per board/profession, statewide.

```json
{ "aggregate": true, "groupBy": "profession", "maxResults": 10 }
```

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold.** Billed only for the rows you use, and each record is metered individually.

New Jersey's register is **four flat files totalling ~521 MB with no query server behind it** - there is no way to ask the state for "just active nurses in Bergen County". Rather than make every lookup pay for a full-register download, the register is **mirrored and unified**, and each run queries the mirror in a single pass. That mirror is what lets a two-million-row register behave like a live lookup at per-record pricing. Every **refresh** is integrity-checked against the register's known shape (file set and datestamp, header tokens, total-row floor, key-column coverage), so a degraded or schema-changed source **fails loudly at refresh** instead of publishing bad rows.

### Example output

**`licenseNumber=25MA00045800`** - a suspended physician carrying a discipline flag:

```json
{
 "platform": "nj-professional-licenses",
 "source": "nj-dca-licensees",
 "state": "NJ",
 "entityType": "individual",
 "scope": "all",
 "professionName": "Medical Examiners",
 "licenseType": "Medical Doctor",
 "licenseNumber": "25MA00045800",
 "status": "Suspended",
 "statusActive": "N",
 "hasDiscipline": "Y",
 "issueDate": "2001-07-23",
 "expirationDate": "2007-06-30",
 "lastRenewalDate": "",
 "licenseMethod": "Archive Record",
 "isOrganization": "N",
 "firstName": "Agatha",
 "middleName": "",
 "lastName": "Catalan",
 "businessName": "",
 "fullName": "AGATHA CATALAN",
 "address1": "400 Chestnut Ridge Road",
 "address2": "",
 "city": "Woodcliff Lake",
 "state": "NJ",
 "zip": "07677",
 "county": "Bergen",
 "country": "United States",
 "refreshed": "2026-10-01",
 "mode": "record",
 "groupKey": "",
 "groupCount": ""
}
```

**`aggregate=true`, `groupBy=status`** - the register by status (top):

```
Active                  834,133
Expired                 815,941
Inactive                246,354
Out of Business          22,704
Deceased                 19,218
```

### Notes on the data

- **`county` and `city` are the licence holder's raw mailing-address fields**,
  taken from the state's own file - they are **not** normalised to New Jersey's
  21 counties. About **74%** of non-empty `county` values match an NJ county;
  the rest are out-of-state or malformed strings (the tail includes single-use
  values). Treat them as free-text address fragments, not an administrative
  geography. `profession` and `status` are the clean, closed dimensions.
- **`aggregate` returns every group and is not cut by `maxResults`.** `profession`
  (49), `entityType` (2) and `status` (15) are small; `county` (~4.4k) and
  `city` (~34.6k) are large - a `groupBy=city` run returns tens of thousands of
  rows and is billed per row. Use a filter (county / profession / status) before
  grouping by city.
- `hasDiscipline=false` returns only records the source **explicitly** marks as
  carrying no discipline flag. Records whose source file omits the flag entirely
  (the active-only roster) are **excluded**, not assumed clean - so this is a
  positive match, not "everything else".

### Source

- [NJ Division of Consumer Affairs - Standard Files](https://app.box.com/v/DCAStandardFiles) - the official free public list of "the entire database of professional licensees" that this actor reads.
- License data is the Division's own published record as of the file's datestamp; it reflects the register at that refresh, and a person's own record is authoritative.

# Actor input Schema

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

lookup = one license number's record(s). aggregate = one row per group. Leave blank to auto-route: a bare licenseNumber -> lookup; any other filter -> search; nothing -> aggregate.

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

Exact NJ license number, e.g. "20CE00212300" or "13VH12779100". Returns the matching record(s).

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

Matches the licensee's full name or business name, substring, case-insensitive.

## `lastName` (type: `string`):

Individual last name substring, case-insensitive.

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

Licensee city, substring, case-insensitive (e.g. "Newark", "Jersey City").

## `county` (type: `string`):

County name, exact match, case-insensitive (e.g. "Bergen", "Essex", "Monmouth").

## `zipCode` (type: `string`):

ZIP prefix, digits only (e.g. "08807").

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

License/credential type, substring, case-insensitive. Examples: "Reg. Prof. Nurse", "Medical Doctor", "Certified Public Accountant", "Home Improvement".

## `profession` (type: `string`):

Regulating board / profession, substring, case-insensitive (e.g. "Nursing", "Pharmacy", "Cosmetology", "Accountancy").

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

Exact status, case-insensitive. Common: Active, Expired, Inactive, Closed, Pending, Out of Business, Deceased, Retired, Voluntary Surrender.

## `entityType` (type: `string`):

individual = a person's license; facility = a business/facility license.

## `statusActive` (type: `boolean`):

true = only currently Active licenses; false = only non-Active; leave unset for all.

## `hasDiscipline` (type: `boolean`):

true = only licensees carrying a discipline flag in the register; false = only those without; leave unset for all. (Flag is present on the 'all statuses' records only.)

## `expirationFrom` (type: `string`):

Earliest license expiration date (inclusive). Accepts "YYYY" or "YYYY-MM" or "YYYY-MM-DD". A date filter only returns records that carry an expiration date.

## `expirationTo` (type: `string`):

Latest license expiration date (inclusive). Accepts "YYYY" or "YYYY-MM" or "YYYY-MM-DD".

## `aggregate` (type: `boolean`):

When on, returns one summary record per group (with a count) instead of individual license records.

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

profession -> the board/profession mix; entityType -> individuals vs facilities; status -> active vs expired vs inactive; county / city -> geographic distribution.

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

Cap the number of records pushed. The aggregate mode returns every group in full and is not cut by this cap.

## Actor input object example

```json
{
  "aggregate": false,
  "groupBy": "profession",
  "maxResults": 200
}
```

# Actor output Schema

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

New Jersey professional license 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/nj-professional-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/nj-professional-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/nj-professional-licenses --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,j0401/nj-professional-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/5jnbrnuFxZQ9hCdwo/builds/atmWK1wsROjRwcdlX/openapi.json
