Mn APIbcegl.hlb.state.mn.us ↗
Search and retrieve Minnesota cosmetology licensee profiles via the MN Board of Cosmetology public verification service. Lookup by name, business, or license number.
What is the Mn API?
This API exposes 2 endpoints covering the Minnesota Board of Cosmetology public license verification service, returning licensee name, city, state, license numbers, license types, statuses, and expiration dates. Use search_licensees to query across thousands of licensees by last name, first name, business name, or license number, and get_licensee_profile to retrieve the complete license history and disciplinary flag for a specific individual.
curl -X GET 'https://api.parse.bot/scraper/6f34b419-fb52-428a-b557-628acbd07816/search_licensees?last_name=Anderson' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace bcegl-hlb-state-mn-us-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: Minnesota Board of Cosmetology license lookup — bounded, re-runnable."""
from parse_apis.bcegl_hlb_state_mn_us_api import MnCosmetology, LicenseeNotFound
client = MnCosmetology()
# Search for licensees by last name; limit= caps total items yielded.
for summary in client.licensee_summaries.search(last_name="Anderson", limit=5):
print(summary.name, summary.city, summary.state)
# Drill into the first match's full profile.
hit = client.licensee_summaries.search(last_name="Anderson", limit=1).first()
if hit is not None:
try:
profile = hit.details(last_name="Anderson")
except LicenseeNotFound:
print("Licensee no longer found for entity", hit.entity_id)
else:
print(profile.name, profile.city, profile.state, profile.zip)
print("Disciplinary action:", profile.disciplinary_action)
# Walk current and expired licenses on the profile.
for lic in profile.current_licenses:
print(" [current]", lic.license_type, lic.license_number, lic.license_status,
"expires", lic.expiration_date)
for lic in profile.expired_licenses:
print(" [expired]", lic.license_type, lic.license_number, lic.license_status)
# Direct point-lookup when entity_id is already known.
detail = client.licensees.get(entity_id="1562810", last_name="Anderson")
print(detail.name, "as of", detail.as_of_date)
print("exercised: licensee_summaries.search / details / licensees.get")
Searches the Board of Cosmetology License Search Service and returns every matching licensee in a single call (the site returns all matches on one page; a last-name-only search for a common surname returned 313 rows). Each row carries the licensee's display name, city, state and the numeric entity_id that get_licensee_profile consumes. Name fields match exactly unless a trailing * wildcard is used (e.g. Ander* matches Anderson and Andersen; Ab* on first_name matches Abby and Abigail). At least one search field must be supplied, otherwise a stale_input error is returned; the typical lookup supplies last_name and optionally first_name, and a license_number-only search returns the single holder of that license. A search with no matches returns an empty results array with total_results 0. The site does not display licenses that have been expired for more than 7 years; that notice is returned as-is in the notice field. Results include out-of-state licensees, so state is not always MN.
| Param | Type | Description |
|---|---|---|
| last_name | string | Licensee last name, exact match or with a trailing * wildcard (e.g. Ander*). Omit only when searching by another field. |
| first_name | string | Licensee first name, exact match or with a trailing * wildcard (e.g. Ab*). Omitted = not filtered on first name. |
| business_name | string | Salon or business name filter as offered by the site's search form (exact or trailing * wildcard). Omitted = not filtered. Not exercised in this build beyond being passed through to the site. |
| license_number | string | License number filter (e.g. the license_number value shown on a profile). Returns the single licensee holding that license. Omitted = not filtered. |
{
"type": "object",
"fields": {
"notice": "the site's coverage notice about licenses expired more than 7 years not being displayed",
"results": "array of matching licensees, each with entity_id (numeric string key for get_licensee_profile), entity_type_id, name, city, state",
"total_results": "integer count of rows returned (all matches; the site does not paginate)"
},
"sample": {
"data": {
"notice": "The Board of Cosmetology License Search Service does not display licenses that have been expired for more than 7 years.",
"results": [
{
"city": "Lake Park",
"name": "Abby Sue Anderson",
"state": "MN",
"entity_id": "1468768",
"entity_type_id": "4"
},
{
"city": "Sandstone",
"name": "Abigail A Anderson",
"state": "MN",
"entity_id": "1562810",
"entity_type_id": "4"
},
{
"city": "Waconia",
"name": "Abigail M Anderson",
"state": "MN",
"entity_id": "1571773",
"entity_type_id": "4"
}
],
"total_results": 3
},
"status": "success"
}
}About the Mn API
Endpoints and What They Return
The search_licensees endpoint accepts last_name, first_name, business_name, and license_number as optional filter parameters. Each supports exact or trailing-wildcard matching (e.g., Ander*). The response includes a results array where each row contains entity_id, entity_type_id, name, city, and state. The entity_id field is the key used to fetch a full profile. The endpoint returns all matches in a single response — a wildcard surname search for a common name returned 313 rows — and a total_results integer count is included alongside a notice about licenses expired more than 7 years ago not being displayed.
License Profile Detail
The get_licensee_profile endpoint requires entity_id (from search results) and last_name, with an optional first_name. It returns name, city, state, zip, business_name, as_of_date, and two arrays: current_licenses and expired_licenses. Each license record in those arrays carries license_type, license_type_id, license_number, license_status, original_license_date, expiration_date, and retired_date. The profile also surfaces a disciplinary_action flag and, where applicable, a salon-manager designation.
Coverage and Scope
Data covers only licensees in the Minnesota Board of Cosmetology system. Licenses expired more than 7 years ago are not displayed, as noted in the notice field returned by search_licensees. The as_of_date field in profile responses indicates the date the source reports the data current as of. Entity type code 4 has been observed for individual licensees; business entities may use different codes.
The Mn API is a managed, monitored endpoint for bcegl.hlb.state.mn.us — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when bcegl.hlb.state.mn.us changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official bcegl.hlb.state.mn.us API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Verify that a cosmetologist or esthetician holds a current Minnesota license before hiring
- Check expiration dates on active licenses for a salon's staff roster using get_licensee_profile
- Look up whether a licensee has a disciplinary_action flag on their public record
- Retrieve license history for a named individual across both current_licenses and expired_licenses arrays
- Search for all licensees associated with a specific salon or business name using the business_name parameter
- Build a license monitoring tool that tracks expiration_date changes for a set of entity_ids
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.