# Florida Building Permits & Code Violation Leads (`open-records-data/florida-building-permits-code-violations`) Actor

Fresh Florida building permits and open code-violation cases from official Miami, Miami-Dade and Orlando open-data feeds. Filter by trade, value or keyword; optional 0-100 lead scores for roofers, solar/HVAC installers, suppliers and property investors. No phones or emails scraped.

- **URL**: https://apify.com/open-records-data/florida-building-permits-code-violations.md
- **Developed by:** [Nathan Madrishin](https://apify.com/open-records-data) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 permit / code 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

## Florida Building Permits & Code Violations API (Miami, Miami-Dade, Orlando)

**Fresh building permits and open code-violation cases from official Florida open-data feeds - as clean JSON, CSV or Excel, with optional 0-100 lead scores.** No API keys, no logins, no proxies, no browser scraping: it reads the cities' and county's own public data APIs, so it is fast, stable and cheap.

Use it to find out **who just pulled a big permit** and **which properties are in trouble** - this week, not last year.

> **At a glance (for people, scripts and AI agents):** input `dataType` (`permits`, `codeViolations` or `both`), `daysBack`, optional filters (`sources`, `keywords`, `commercialOnly`, `minEstimatedValue`, `codeStatus`) and `enrich` for 0-100 lead scores; output is one flat JSON record per permit or code case. Defaults return 100 fresh records in seconds. Covers Orlando, Miami-Dade County and the City of Miami. From $4 per 1,000 records. Ready-made snippets for MCP, curl, Python and JavaScript are under "Use it from AI agents, code and no-code tools".

### Who it is for

| You are a... | Try this |
|---|---|
| Roofer, solar, HVAC, electrical, plumbing or pool contractor | Permits, `commercialOnly`, keywords like `roof`, `solar`, `hvac` |
| Building-materials supplier or equipment dealer | Permits with `minEstimatedValue` (e.g. $100,000+) and `enrich` on |
| Real-estate investor or wholesaler | Code violations, `codeStatus: open`, `enrich` on - lien and civil cases, unsafe structures, expired permits |
| Property manager or insurance / restoration company | Code violations at addresses you serve |
| Broker, developer or market analyst | Permits over time by jurisdiction, value and trade |
| Sales team / lead-gen agency | Scheduled daily runs into Google Sheets or your CRM |

### What you get

| Source | Data | Updated | Date filter |
|---|---|---|---|
| City of Orlando | Permit applications (building, mechanical, electrical, plumbing, roofing, fire, engineering...) | daily | application processed date |
| Miami-Dade County | Issued building permits | daily | permit issued date |
| City of Miami | Building permits since 2014 (thousands of new ones every month) | daily | permit issued date |
| City of Orlando | Code-enforcement cases | daily | case opened date |
| Miami-Dade County | Code-compliance cases, including lien, civil-penalty and collections referrals | daily | case opened date |
| Miami-Dade County | Building violations: unsafe structures, expired permits, boilers, other | daily | case opened date |

**Every permit** has: permit number, type, work type, status, estimated project value, square footage, dates, address, parcel / folio number, the contractor company, and the owner - only when the owner is a business or government entity.

**Every code case** has: case number, type, status, open / closed flag, opened date, address, parcel / folio number, a plain issue description, severity flags (`unsafe`, `unpermitted-work`, `expired-permit`, `vacant`, `overgrown`...), and whether a lien was referred.

### Lead scoring (`enrich: true`)

Turn a raw feed into a ranked call list. Every record gets a 0-100 score and human-readable `scoreReasons`, and the best leads come first.

- **Permits:** project value, commercial flag, how new it is, trade tags (roofing, solar, hvac, electrical, plumbing, pool, demolition, remodel, fire-protection, sign...) and whether the owner is a business entity.
- **Code cases:** open status, age, escalation (lien, civil penalty, collections referral), severity flags, vacant land use and the number of cases at the same address - a transparent "distressed property" indicator.

### Quick start - copy one of these inputs

**Big commercial projects in Miami this fortnight**

```json
{
  "dataType": "permits",
  "sources": ["miami-city", "miami-dade"],
  "commercialOnly": true,
  "minEstimatedValue": 100000,
  "daysBack": 14,
  "enrich": true,
  "maxResults": 200
}
```

**Distressed-property leads: open code cases, worst first**

```json
{
  "dataType": "codeViolations",
  "codeStatus": "open",
  "daysBack": 90,
  "enrich": true,
  "maxResults": 500
}
```

**Every new solar or roofing permit in the last month**

```json
{
  "dataType": "permits",
  "keywords": ["solar", "roof"],
  "daysBack": 30,
  "maxResults": 1000
}
```

Run with the defaults to get 100 fresh permits, shared evenly across every source (Orlando's impact-fee billing entries are left out - only real construction permits). `dataType: "both"` returns a balanced mix of permits and code cases.

### Input

| Field | Default | Notes |
|---|---|---|
| `dataType` | `permits` | `permits`, `codeViolations`, or `both` (results are shared between the two types) |
| `sources` | all | `orlando`, `miami-dade`, `miami-city`. Code violations: Orlando and Miami-Dade |
| `daysBack` | 30 | 1-365 |
| `commercialOnly` | false | permits only |
| `minEstimatedValue` | 0 | permits only, USD |
| `keywords` | - | keep records matching any keyword (type, work type, description, address, contractor, issue flags) |
| `codeStatus` | `open` | `open` (not closed, includes lien / civil / referred cases) or `all` |
| `includeTickets` | false | Orlando "ticket" cases (mostly street-level transient enforcement) are skipped by default |
| `enrich` | false | adds scores, reasons, trade tags, cases-at-address; billed at the scored-lead rate |
| `maxResults` | 100 | hard cap on returned **and billed** records (max 5,000); your run's maximum-charge setting is honoured too |
| `socrataAppToken` | - | optional; raises the Orlando API rate limit |

### Output example (abridged)

A permit:

```json
{
  "recordType": "permit", "source": "miami-city", "jurisdiction": "City of Miami, FL",
  "permitNumber": "BD25000255019B001", "permitType": "NEW CONSTRUCTION", "isCommercial": true,
  "status": "Active", "estimatedValue": 980000, "issuedDate": "2026-09-18",
  "address": "1785 NW 35 ST", "parcelId": "0131270090140",
  "contractorCompany": "OCEAN DOORS AND WINDOWS. INC.",
  "tags": ["new-construction"], "score": 79,
  "scoreReasons": ["project value >= $100k", "commercial permit", "new activity in last 7 days", "trades: new-construction"]
}
```

A code case:

```json
{
  "recordType": "codeViolation", "source": "miami-dade", "jurisdiction": "Miami-Dade County, FL",
  "caseNumber": "20260250634", "caseType": "Unsafe Structure", "status": "Open", "isOpen": true,
  "openedDate": "2026-09-17", "address": "19422 SW 119 CT", "parcelId": "3069010270170",
  "ownerName": "P&B GLOBAL PROPERTIES LLC", "ownerType": "entity",
  "issueFlags": ["unsafe", "structural"], "score": 50,
  "scoreReasons": ["case still open", "severity flags: unsafe, structural"]
}
```

Also written, to the run's key-value store: a `SUMMARY` record with the date window, counts per source, warnings, and whether the run stopped at your spending limit. Every field is explained under Output fields below.

### Pricing

Pay per event - you only pay for records you actually receive:

- **$4.00 per 1,000 records** (`enrich` off)
- **$20.00 per 1,000 scored lead records** (`enrich` on)
- **$0.005** per run start

Set a maximum charge on the run and it stops there. Compare that with subscription lead lists: a $4 run gets you 1,000 fresh records.

### Privacy by design

This Actor is deliberately **not a contact scraper**.

- No phone numbers or e-mail addresses are collected.
- Private individuals' names (homeowners, violators, complainants) are not returned. Owners appear only when the name is clearly a business or government entity; otherwise `ownerType` is `individual` and `ownerName` is `null`. Use the parcel / folio number to look the property up in the county property appraiser's public records.
- Individual contractor / licensee names, contractor street addresses and architect names are dropped; the contractor **company** name is kept.
- Free-text code-case comments are never output (citizen complaints often contain the complainant's name, phone and address). Only generic severity flags derived from them are.
- Confidential and protected cases published by the county are skipped.

### Use it from AI agents, code and no-code tools

The Actor is built to be called by machines: a run with the defaults finishes in seconds, every input has a safe default, every field is documented below, and the output is flat, typed JSON with a stable schema. There is no login, proxy or browser to configure.

**AI agents (MCP).** Add the Apify MCP server and expose just this Actor as a tool:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=open-records-data/florida-building-permits-code-violations"
    }
  }
}
```

Works with Claude, Cursor, VS Code and any MCP client. Sign in with OAuth, or send an `Authorization: Bearer <APIFY_TOKEN>` header. Then just ask, for example: *"Find open unsafe-structure code cases in Miami-Dade from the last 30 days"* or *"List new commercial permits over $250,000 in Miami this week."*

**HTTP API (one call, JSON back):**

```bash
curl -X POST "https://api.apify.com/v2/acts/open-records-data~florida-building-permits-code-violations/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"dataType":"permits","commercialOnly":true,"minEstimatedValue":100000,"daysBack":14,"enrich":true,"maxResults":50}'
```

**Python:**

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("open-records-data/florida-building-permits-code-violations").call(
    run_input={"dataType": "codeViolations", "codeStatus": "open", "daysBack": 30, "enrich": True, "maxResults": 100}
)
for lead in client.dataset(run["defaultDatasetId"]).iterate_items():
    if lead.get("recordType") == "codeViolation":
        print(lead["score"], lead["address"], lead["caseType"], lead["scoreReasons"])
```

**JavaScript:**

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('open-records-data/florida-building-permits-code-violations')
    .call({ dataType: 'permits', keywords: ['roof', 'solar'], daysBack: 30, maxResults: 200 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**Schedules and integrations.** Put it on a schedule (daily is typical), then send results anywhere: Google Sheets, Airtable, Slack or e-mail via Apify integrations, Zapier, Make or n8n, or a webhook into your CRM.

**Tips for agents.**

- Start with the defaults and a small `maxResults` (10-20) to see the shape of the data, then widen.
- Skip `enrich` when you only need raw records: it costs more per record but ranks the results and explains the ranking.
- Filter records with `recordType` (`permit` or `codeViolation`) and `source` (`orlando`, `miami-dade`, `miami-city`).
- Run totals, per-source counts, the date window and any per-source warnings are in the `SUMMARY` record of the run's key-value store. Check it if a source returns fewer records than expected.
- Records are public-record data with owner and contractor personal data removed. Do not use them for tenant screening, credit, insurance or employment decisions.

### Output fields

| Field | Type | Meaning |
|---|---|---|
| `recordType` | `permit` | `codeViolation` | What kind of record this is |
| `source`, `jurisdiction` | string | `orlando`, `miami-dade` or `miami-city`, and the readable name |
| `permitNumber` / `caseNumber` | string | The jurisdiction's own identifier |
| `permitType`, `workType`, `description` | string | What the permit is for (permits only) |
| `caseType`, `caseName`, `description` | string | What the case is about (code cases only) |
| `status`, `isOpen` | string, boolean | Jurisdiction status; `isOpen` is true while a code case is not closed |
| `isCommercial` | boolean or null | Commercial vs. residential where the jurisdiction says |
| `estimatedValue` | number (USD) or null | Declared project value |
| `squareFootage` | number or null | Permit square footage when published |
| `appliedDate`, `issuedDate`, `activityDate` | `YYYY-MM-DD` | Application, issue and most recent of the two |
| `openedDate`, `closedDate` | `YYYY-MM-DD` | Code case dates |
| `address`, `parcelId` | string | Street address and parcel / folio number |
| `ownerName`, `ownerType` | string or null, `entity` | `individual` | `unknown` | Name only when the owner is a business or government entity |
| `contractorCompany` | string or null | Contractor company (never an individual) |
| `issueFlags` | string\[] | Code cases: `unsafe`, `structural`, `unpermitted-work`, `expired-permit`, `vacant`, `overgrown`... |
| `lienReferral` | boolean | Miami-Dade code cases: a lien or collections referral is on file |
| `tags` | string\[] | Permits, with `enrich`: trade tags such as `roofing`, `solar`, `hvac` |
| `score`, `scoreReasons` | 0-100, string\[] | With `enrich`: lead score and the plain-language reasons |
| `casesAtAddress` | number | With `enrich`: code cases at the same address in this run |
| `sourceUrl` | string | The official open-data page the record came from |

### FAQ

**Is this legal?** It reads public records that the cities and county publish for reuse through their official open-data APIs. It is not affiliated with or endorsed by any of them.

**Can I use it for tenant screening, credit, insurance or hiring decisions?** No. It is public-record data, not a consumer report, and must not be used for purposes regulated by the FCRA.

**How fresh is the data?** As fresh as each jurisdiction publishes it - all sources update daily. Orlando permits are filtered by application processed date, so newly filed applications appear before they are issued (`issuedDate` may be empty). Miami-Dade and City of Miami permits are issued permits.

**Why is the owner missing on most permits?** Owners of homes are individuals, so their names are withheld by design. Business owners are shown. City of Miami permits carry no owner field.

**Is the score a prediction?** No. It is a transparent heuristic for triage: the `scoreReasons` tell you exactly why a record ranks where it does.

**What if a city changes its data?** The Actor reports per-source failures in the `SUMMARY` record and in the log rather than silently returning nothing, and keeps returning data from the other sources.

**Does it cover all of Florida?** Not yet. Today: the City of Orlando, Miami-Dade County (as published in the county's open-data feeds) and the City of Miami. Each jurisdiction runs its own permit system, so cities are added one at a time as they publish usable open data.

**How do I get roofing, solar or HVAC leads?** Run permits with `keywords` such as `["roof"]`, `["solar"]` or `["hvac"]`, set `commercialOnly` or `minEstimatedValue` to focus on bigger jobs, turn `enrich` on to rank them, and schedule a daily run.

**Will you add more cities?** Yes - requests for more Florida jurisdictions are welcome. Open an issue on the Issues tab and say which city and which data (permits or code cases).

### More Florida public-record Actors

- [Florida New Business Leads (Miami-Dade, Broward, Miami)](https://apify.com/open-records-data/florida-new-business-leads) - businesses the week they are licensed, or before they open, from official business tax receipt feeds, with optional 0-100 lead scores. Pair it with this Actor to reach new businesses that are also pulling permits.
- [Miami-Dade Property Records API](https://apify.com/open-records-data/miami-dade-property-records) - look up any Miami-Dade address or folio, or search by ZIP and sale date, for property facts, FEMA flood zone, permits, violations and a 0-100 prospecting score. Use it to enrich the addresses this Actor returns.

### Limitations

- Owner classification is a name heuristic. Some entities without a legal suffix (for example a bare association name) are treated as individuals and withheld. It errs on the side of privacy.
- Coverage today is Orlando, Miami-Dade County and the City of Miami; more Florida jurisdictions are on the roadmap.
- Data is only as accurate as the jurisdiction publishes it. Miami-Dade's electrical, mechanical and other sub-permits often repeat the whole project's estimated value, so several permits for one project can show the same (large) number.
- Code cases with no street address are skipped.

# Actor input Schema

## `dataType` (type: `string`):

Building permits (new projects), code violations (distressed / neglected properties), or both mixed together.

## `sources` (type: `array`):

Permits: City of Orlando, Miami-Dade County, City of Miami. Code violations: City of Orlando and Miami-Dade County (code compliance + building violations). Leave all selected for statewide-style coverage of South and Central Florida.

## `daysBack` (type: `integer`):

Only records from the last N days: applications processed (Orlando permits), permits issued (Miami-Dade and City of Miami) or cases opened (code violations).

## `commercialOnly` (type: `boolean`):

Permits only. Skip residential permits.

## `minEstimatedValue` (type: `integer`):

Permits only. Skip permits below this estimated value.

## `keywords` (type: `array`):

Keep only records that mention any of these words in the type, description, address, contractor or issue flags. Trade examples: roof, solar, hvac, pool, demolition, electrical, plumbing, fire sprinkler, sign, unsafe, vacant.

## `codeStatus` (type: `string`):

Code violations only. "Open" means not closed - including cases already escalated to a lien, civil penalty or collections referral (the best distressed-property signals).

## `includeTickets` (type: `boolean`):

Code violations only. Orlando "ticket" cases (mostly street-level transient enforcement) are skipped by default; cases with no street address are always skipped.

## `enrich` (type: `boolean`):

Adds a 0-100 lead score with plain-English reasons, trade tags (permits) and cases-at-address counts (code violations), and sorts the best leads first. Billed at the higher scored-lead rate.

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

Upper bound on records returned and billed. Your run's maximum-charge setting is honoured too, so you can never be billed more than you set.

## `socrataAppToken` (type: `string`):

Optional. Raises the City of Orlando API rate limit. Free from the Socrata developer portal.

## Actor input object example

```json
{
  "dataType": "permits",
  "sources": [
    "orlando",
    "miami-dade",
    "miami-city"
  ],
  "daysBack": 30,
  "commercialOnly": false,
  "minEstimatedValue": 0,
  "keywords": [
    "roof",
    "solar"
  ],
  "codeStatus": "open",
  "includeTickets": false,
  "enrich": false,
  "maxResults": 100
}
```

# Actor output Schema

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

Permit and code-violation records in the run's default dataset.

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

Counts per source, applied filters and warnings.

# 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 = {
    "keywords": [
        "roof",
        "solar"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("open-records-data/florida-building-permits-code-violations").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 = { "keywords": [
        "roof",
        "solar",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("open-records-data/florida-building-permits-code-violations").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 '{
  "keywords": [
    "roof",
    "solar"
  ]
}' |
apify call open-records-data/florida-building-permits-code-violations --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,open-records-data/florida-building-permits-code-violations"
        }
    }
}
```

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/PJMYLUqnZ475grNa0/builds/rMyXzwdx7jU1lZ3c4/openapi.json
