# HdL Municipal Business License Lookup (`muhammadafzal/hdl-municipal-business-license-lookup`) Actor

Search official public HdL municipal business-license records by business name, street address, or city category. Returns source-reported account numbers, addresses, and dates.

- **URL**: https://apify.com/muhammadafzal/hdl-municipal-business-license-lookup.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 municipal 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.

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

## HdL Municipal Business License Lookup

Search public business-license records from HdL Companies municipal portals by city, business name, street address, or a city's business-type category. Enter one or more HdL portal URLs and receive the account number, business name, dates, address, and source page as structured dataset records.

This Actor queries each city's own public search form. It does not search every HdL city automatically, access private license-holder accounts, or establish that a license is currently valid.

### Records returned

| Field | Meaning |
|---|---|
| **licenseAccountNumber** | Account number shown by the city portal; this may not be a statewide or professional license number |
| **businessName** | Business name displayed in the public search results |
| **startDate** | Start date displayed by the portal, normalized to YYYY-MM-DD when recognized |
| **expirationDate** | Expiration date displayed by the portal; it is not a current-status determination |
| **address** | Business address displayed in the result |
| **portalHost** | HdL municipal portal that supplied the record |
| **sourceUrl** | Public business search page for that portal |
| **scrapedAt** | UTC retrieval time |

Optional values are returned as null. The source search page may expose only a subset of a license account's details. The Actor does not infer an active, compliant, or valid status from the dates.

#### Output example

```json
{
  "licenseAccountNumber": "00209617",
  "businessName": "Starbucks Coffee #10112",
  "startDate": "2006-06-23",
  "expirationDate": "2027-06-30",
  "address": "68 RIO RANCHO RD, POMONA, CA 91766-4898",
  "portalHost": "pomona.hdlgov.com",
  "sourceUrl": "https://pomona.hdlgov.com/Search/Index/BusinessLicense",
  "scrapedAt": "2026-09-24T06:27:47.910Z"
}
```

### Search a city portal

Find the HdL business-license portal linked by the municipality, then provide its base URL. For example, the [City of Pomona portal](https://pomona.hdlgov.com/) links to a public business search.

| Input | Type | Default | Details |
|---|---|---|---|
| portalUrls | array of URLs | https://pomona.hdlgov.com | One to 10 HTTPS municipal hosts ending in .hdlgov.com; each should be a portal base URL |
| searchType | select | businessName | Choose business name, business address, or business type |
| query | string | Starbucks | Name/type searches allow 50 characters; address searches allow 255 |
| maxResults | integer | 5 | Maximum unique records across all portals, from 1 to 1,000 |

For a business-type search, use a category exactly as it appears in that city's portal. Category lists differ by municipality. For an address search, enter the street portion; city portals may ask you to omit city, state, and ZIP.

#### Example input

```json
{
  "portalUrls": ["https://pomona.hdlgov.com"],
  "searchType": "businessName",
  "query": "Starbucks",
  "maxResults": 5
}
```

Search two cities with the same business name:

```json
{
  "portalUrls": [
    "https://pomona.hdlgov.com",
    "https://novato.hdlgov.com"
  ],
  "searchType": "businessName",
  "query": "Starbucks",
  "maxResults": 25
}
```

The result limit applies across all selected portals, which are searched sequentially. Duplicate account numbers are removed within the same city portal.

#### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~hdl-municipal-business-license-lookup/runs" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"portalUrls":["https://pomona.hdlgov.com"],"searchType":"businessName","query":"Starbucks","maxResults":5}'
```

Keep Apify tokens in an authorization header or secret manager. Do not put them in Actor input.

### Pricing

This Actor uses pay-per-event pricing. The apify-actor-start event is automatic and the apify-default-dataset-item event applies to each record saved to the default dataset. There is no separate custom charge for the same result. Platform usage remains the Actor owner's cost; event prices must cover compute and any configured proxy usage.

| Event | FREE | BRONZE | SILVER | GOLD |
| --- | ---: | ---: | ---: | ---: |
| Actor start (one-time) | $0.005 | $0.005 | $0.005 | $0.005 |
| Municipal license record | $0.005 | $0.004875 | $0.00475 | $0.004 |

The event totals by tier are $0.010 / $0.009875 / $0.00975 / $0.009 for one record, $0.030 / $0.029375 / $0.02875 / $0.025 for five records, and $0.130 / $0.126875 / $0.12375 / $0.105 for 25 records (FREE / BRONZE / SILVER / GOLD). Set maxTotalChargeUsd to at least $0.010 to cover the start event and one result. The Actor applies a verified free-plan limit of five records per run and also honors a run-level charge limit.

The price table in .actor/pay\_per\_event.json is the local pricing definition. Confirm active prices and platform-usage settings in the live Actor configuration before relying on them.

### Access behavior and limits

- The Actor opens the public HdL search page and submits its ordinary business-name, address, or category form over HTTPS.
- It tries direct HTTP first. If a portal returns HTTP 403 or a recognizable security challenge, it tries that city search through the configured, encrypted DataImpulse route, then falls back to Apify residential proxy if DataImpulse is unavailable or remains blocked. Proxy URLs are never Actor inputs or logs. Platform proxy usage and any external proxy-provider charges are separate costs for the Actor owner; a remaining denial is reported as BLOCKED.
- City portals are separate tenants. The portal URL must be linked by the municipality and must use an HdL subdomain.
- Portals that return an access denial, Cloudflare challenge, or unsupported form layout are reported in SUMMARY; no CAPTCHA or authentication is bypassed.
- Results are read from the page returned by the city's search form. If that page reports more matches than the Actor returns, maxResults controls saved records. Very broad searches may return a large source page; direct pages over 3 MB and proxied pages over 250 KB fail with a prompt to narrow the search.
- Requests are sequential and bounded. The Actor makes up to three attempts for retryable network, server, or rate-limit failures and stops after its run-time budget.
- A valid search with no match writes zero dataset items and an EMPTY outcome. Access denials are BLOCKED; invalid inputs or unavailable business-type categories are REJECTED; an unexpected source or parsing error is FAILED. Partial results remain available if a later city portal fails.

The SUMMARY key-value record contains the outcome, source and saved-result counts, per-city diagnostics, and warnings. Dataset rows contain only business records.

### Responsible use

These are public municipal records, but an address may identify a home-based business or sole proprietor. Follow the source municipality's terms and applicable privacy, marketing, and data-retention rules. Independently confirm important records with the municipality before making compliance, enforcement, credit, employment, housing, insurance, or other high-impact decisions. HdL Companies and each municipality remain the authoritative sources.

### Support

When reporting a problem, include the Actor run ID, the public portal host, search type, and the SUMMARY outcome. Omit tokens and private license-holder details.

# Actor input Schema

## `portalUrls` (type: `array`):

Use one or more official municipal HdL portals, such as \["https://pomona.hdlgov.com"]. Enter portal base URLs only; the Actor opens each portal's public business search. Maximum 10 cities per run.

## `searchType` (type: `string`):

Choose the public portal field to search. Business type must exactly match a category listed by that city's portal.

## `query` (type: `string`):

Enter a business name, street address, or exact business-type category from the selected portal. Example: Starbucks. Name and type searches allow up to 50 characters; addresses allow up to 255.

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

Maximum unique license records to save across all selected cities. Default 5; paid runs may request up to 1,000. Free-plan runs are capped at 5 records.

## Actor input object example

```json
{
  "portalUrls": [
    "https://pomona.hdlgov.com"
  ],
  "searchType": "businessName",
  "query": "Starbucks",
  "maxResults": 5
}
```

# Actor output Schema

## `records` (type: `string`):

HdL account number, business name, source dates, address, city portal, and source search page.

## `summary` (type: `string`):

Search outcome, record counts, portal diagnostics, warnings, and timestamps.

# 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 = {
    "portalUrls": [
        "https://pomona.hdlgov.com"
    ],
    "searchType": "businessName",
    "query": "Starbucks",
    "maxResults": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/hdl-municipal-business-license-lookup").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 = {
    "portalUrls": ["https://pomona.hdlgov.com"],
    "searchType": "businessName",
    "query": "Starbucks",
    "maxResults": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/hdl-municipal-business-license-lookup").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 '{
  "portalUrls": [
    "https://pomona.hdlgov.com"
  ],
  "searchType": "businessName",
  "query": "Starbucks",
  "maxResults": 5
}' |
apify call muhammadafzal/hdl-municipal-business-license-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/hdl-municipal-business-license-lookup"
        }
    }
}
```

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/ZdvXy433pkUr4lHhW/builds/Tc1ILMUSSO7ifdlK1/openapi.json
