# FDD Item 19 Parser — Franchise AUV & Financial Performance (`silentshadow55/fdd-item19-actor`) Actor

Search state franchise registries (Minnesota CARDS + Wisconsin DFI), download Franchise Disclosure Document PDFs, and extract Item 19 Financial Performance Representations — has-FPR flag, raw Item 19 text, every dollar figure, and best-effort average/median/high/low unit volume. No logins.

- **URL**: https://apify.com/silentshadow55/fdd-item19-actor.md
- **Developed by:** [Esteban Ortega](https://apify.com/silentshadow55) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $600.00 / 1,000 parsed fdds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## FDD Item 19 Parser — Franchise AUV & Financial Performance Representations

Extract **Item 19 (Financial Performance Representations)** and the **average unit volume (AUV)** from **Franchise Disclosure Documents (FDDs)** — automatically. This actor searches the official **Minnesota CARDS** franchise registry, downloads the FDD PDF, and returns the Item 19 section as structured data: a `has_fpr` flag, the raw Item 19 text, every dollar figure, and — for simple summary tables — the headline **average / median / high / low** unit volume. No CAPTCHAs, no logins, no API keys.

> **Clean provenance, by design.** Every number traces to a public state-government filing you can open yourself — no paywall scraping, no gray-area data. That's the provenance standard lenders, brokers, and franchise attorneys actually need.

Built for franchise researchers, franchise brokers, franchise-buyer due-diligence, and anyone building a dataset of franchise earnings claims.

### What it does

Give it a franchise name (e.g. `Jersey Mike's`) or a year + document-type sweep. For each franchise name it will:

1. **Search** the Minnesota CARDS franchise registry — full search, complete filing history, and stable per-document PDF links.
2. **Download** only the **newest full FDD** for that name (newest complete document — Clean/Final/Revised FDD; a Marked redline only when nothing complete exists) — never the whole filing history. In sweep mode (a `year` with no names) it downloads matching FDDs up to `maxFdds`.
3. **Locate Item 19** using a longest-span sectioner that reliably picks the document body (not the table-of-contents stub) even when Item 19 is cross-referenced in state addenda.
4. **Parse** the Financial Performance Representation: presence flag, raw text, all dollar figures, a best-effort headline AUV for single-summary-row tables (Jersey Mike's style), and a `complex_table_flag` for multi-quartile grids (Anytime Fitness style) that it deliberately does **not** mis-parse.

### Coverage: one registry, on purpose

This version queries **Minnesota CARDS only** (`states: ["MN"]` — the only supported value). An FDD is a **single national document**, and Minnesota is the registry that exposes the most of it over plain HTTP: name search, the full filing history per franchisor, year sweeps, and stable PDF URLs. Support for a second registry (Wisconsin DFI) is planned for a later version. California and NASAA EFD are excluded because they block automated HTTP access.

Note that CARDS matches `franchiseName` by **substring**, so a short search string can select a franchisor you did not have in mind (searching `Papa` returns *Beard Papa's*). The `franchisor` and `franchise_name` fields on every record tell you exactly which one you got.

### Only real FDDs are downloaded — and billed

A CARDS search returns amendments, consents, deficiency notices and cover letters alongside the disclosure documents. **Only genuine full-FDD document types** (Clean FDD, Final FDD, Revised FDD, Marked FDD) are ever downloaded and charged as an `fdd` record. If a search matches rows but none of them is an FDD, nothing is downloaded, nothing is billed, and an unbilled diagnostic says so.

### Nothing you asked for disappears silently

Every requested franchise name ends the run accounted for — by a billed record, or by an **unbilled** diagnostic in the run log and status message:

| Diagnostic | Meaning |
|---|---|
| `no_results_found` | Searched; the registry returned nothing for that name. |
| `no_fdd_document_in_results` | Searched; rows came back but none is a full FDD document type, so nothing was billed in its place. |
| `already_delivered_under_earlier_query` | Its only document was already delivered under an earlier name, so it was not re-billed. The diagnostic names the record that covers it. |
| `budget_exhausted_name_not_searched` | The `maxFdds` budget ran out before this name was searched at all. The diagnostic says what to raise `maxFdds` to. |
| `duplicate_franchise_name_collapsed` | The name repeats an earlier entry (case- or whitespace-variant), so it was searched and billed once. |
| `mn_search_skipped_no_criteria` | Neither `franchiseNames` nor `year` was given; an empty-criteria sweep would have billed arbitrary FDDs. |
| `franchise_names_all_blank` | `franchiseNames` was supplied but every entry is blank/whitespace. Nothing is searched or billed — the run never reinterprets that as a year sweep. Set `franchiseNames: []` to run a sweep deliberately. |
| `unsupported_state_ignored` / `no_supported_state_selected` | A saved input asked for a state other than `MN`; it was not searched, and it is named rather than quietly dropped. |
| `search_failed` / `download_failed` / `not_a_pdf` | Aggregated failure count and first error for that name. |

None of these is written to the dataset, so none of them is billed.

### Output fields

One record per downloaded FDD (`type: "fdd"`). Every record carries the same key set (rectangular CSV/XLSX exports):

```json
{
  "type": "fdd",
  "state": "MN",
  "sources": ["MN CARDS"],
  "states": ["MN"],
  "scraped_at": "2026-07-27T00:00:00+00:00",
  "franchisor": "A SUB ABOVE, LLC",
  "franchise_name": "JERSEY MIKE'S",
  "mn_file_number": "9229",
  "document_type": "Clean FDD",
  "filing_year": "2026",
  "received_date": "04/10/2026",
  "pdf_url": "https://cards.web.commerce.state.mn.us/documents/{GUID}/download?documentClass=FRANCHISE_REGISTRATIONS&contentSequence=0",
  "pdf_bytes_kvs_key": null,
  "has_fpr": true,
  "item19_status": "extracted",
  "item19_text": "ITEM 19. FINANCIAL PERFORMANCE REPRESENTATIONS ...",
  "item19_char_count": 5824,
  "dollar_figures": ["$1,367,578", "$1,305,850", "$3,228,616", "$512,332"],
  "headline_auv": {
    "average": "$1,367,578",
    "median": "$1,305,850",
    "high": "$3,228,616",
    "low": "$512,332"
  },
  "complex_table_flag": false,
  "source_url": "https://cards.web.commerce.state.mn.us/documents/{GUID}/download?...",
  "source_urls": [
    "https://cards.web.commerce.state.mn.us/documents/{GUID}/download?..."
  ],
  "error": null
}
````

Provenance fields, present and non-empty on **every** record:

| Field | Meaning |
|---|---|
| `state` | The state whose document this record's Item 19 came from — always `MN` in this version. |
| `sources` | Registries that contributed to this record: `["MN CARDS"]`. |
| `states` | The states behind `sources`: `["MN"]`. |
| `source_urls` | Every contributing URL — the FDD PDF URL for an `fdd` record, the CARDS search URL for a diagnostic. |

Every record — `fdd` and `summary` alike — carries the identical full key set in the identical order. Beyond the example above that also includes `document_title`, `pdf_title`, `source`, and the summary-record fields `query`, `fdds_found`, and `failed_count`.

**`has_fpr` never asserts what the parser doesn't know.** It is tri-state: `true` / `false` are reported only when the Item 19 section was actually located in the document; otherwise it is `null` (unknown) and `item19_status` says why:

| `item19_status` | Meaning |
|---|---|
| `extracted` | The Item 19 section was located; `has_fpr` is a real true/false and the `item19_*` fields are populated. |
| `section_not_found` | The PDF's text was extracted but no ITEM 19 → ITEM 20 span was found (unusual layout or heading wording). `has_fpr` is `null` — this is **not** a claim that the franchisor makes no FPR. |
| `no_text_extracted` | The PDF yielded no text at all (typically a scanned image without a text layer). `has_fpr` is `null`. |
| `parse_failed` | Text extraction/analysis raised an error; `error` carries the detail. `has_fpr` is `null`. |

**Search and download failures are not billed at all.** A failed search or a failed/non-PDF download never produces an all-null `fdd` record, never consumes the `maxFdds` budget, and is **never written to the dataset**. Failure diagnostics (aggregated to at most one per requested name, with `failed_count` and the first `error` string) and the non-failure notices in the table above are routed to the **run log** and the run **status message** instead of billed dataset items. The dataset contains `fdd` records and nothing else.

**Records stream.** Each record is pushed to the dataset the moment it is produced — nothing is buffered across franchise names — so a run that times out or migrates late still delivers everything scraped so far.

### Input

| Field | Type | Description |
|---|---|---|
| `franchiseNames` | array | Franchise/franchisor names to search (e.g. `["Jersey Mike's", "Anytime Fitness"]`). Per name, only the newest full FDD is downloaded — normally one record per name. Repeated or whitespace-variant entries are collapsed, and two names resolving to the same document are billed once. |
| `year` | string | Sweep mode: pull a batch of FDDs filed in this year (e.g. `2026`). When combined with `franchiseNames`, restricts each name's results to that filing year. |
| `documentType` | string | Restrict to a document type. Unset means `Clean FDD` — the complete disclosure document, best for Item 19. Pass `""` for "Any document type"; even then only full-FDD document types are downloaded. |
| `states` | array | `["MN"]` — Minnesota CARDS is the only registry this version searches. |
| `maxFdds` | integer | Single global cap on FDD PDFs downloaded + parsed per run, across all names. One downloaded PDF is one billed record, so this is also your hard cost cap. Failures don't count against it. If it runs out before every name is searched, the unsearched names are named in the log. Default 3. |
| `downloadPdfToKvs` | boolean | Also store each raw PDF in the run key-value store (`pdf_bytes_kvs_key`). |
| `requestDelaySeconds` | integer | Politeness delay between requests (default 2s). |
| `proxyConfiguration` | object | Datacenter proxy is sufficient (public government site). |

### Use cases

- **Franchise due diligence** — pull the earnings claims for a shortlist of franchises before buying.
- **Franchise-broker research** — compare unit volumes across concepts in the same category.
- **Franchise earnings datasets** — bulk-collect Item 19 text + dollar figures for analysis or an LLM pipeline.
- **Competitive benchmarking** — track a franchisor's reported AUV year over year.
- **Lead qualification** — see which franchises even make a financial performance representation (`has_fpr`).

### FAQ

#### How do I get Item 19 financial data from an FDD without reading 500 pages?

Point this actor at a franchise name; it downloads the FDD and returns just the Item 19 section plus the extracted dollar figures and headline average/median/high/low.

#### What is the average unit volume (AUV) of a franchise, and where is it in the FDD?

AUV is the average revenue of a brand's units — the headline number of franchise due diligence. It lives in **Item 19** of the FDD, when the franchisor chooses to disclose it (roughly two-thirds now do). This actor returns it as `headline_auv` with the average, median, high, and low, verified against the table's own column order. Always read the footnotes too: brands define AUV differently (company-owned units in or out, top-quartile only, etc.) — which is why the full `item19_text` ships with every record.

#### How do I compare Item 19 earnings claims across multiple franchises?

Pass several names in `franchiseNames` — each returns its newest complete FDD's Item 19 in one run, one record per brand, with identical fields. Export to CSV/XLSX and you have a side-by-side AUV benchmark.

#### Is franchise Item 19 data public?

Yes. Franchisors must register their FDD in registration states, and Minnesota's CARDS registry publishes the full documents. Every record this actor returns links the exact government-hosted PDF it parsed.

#### How much does franchise Item 19 data cost elsewhere?

FRANdata charges about **$220 for a single-FDD report**; Franchimp Pro is **$167/month**. This actor is **$0.60 per parsed FDD** — the same Item 19 numbers, from the same public filings, with a source PDF link on every row.

#### Which franchises even make a financial performance representation?

That's the `has_fpr` flag. It's tri-state and honest: `true` (section found, real FPR), `false` (section found, franchisor declines), or `null` (section couldn't be located — see `item19_status`). Screening a list of brands by `has_fpr` is the fastest first-pass filter in franchise due diligence.

#### Which states does it cover?

Minnesota (CARDS) only in this version. FDDs are national documents and most franchisors register in Minnesota, so franchise coverage is broad even from a single registration state. A second registry (Wisconsin DFI) is planned for a later version; California and NASAA EFD are excluded because they block automated HTTP access.

#### Why did a name I asked for return no record?

Check the run log. Every name that produced no record produces a diagnostic saying which of these happened: nothing matched, the matches were not FDDs, the document was already delivered under an earlier name, the name repeated an earlier entry, or the `maxFdds` budget ran out before it was searched. None of those is billed.

#### Does it need an API key or login?

No. The source is a public state-government franchise registry served over plain HTTP.

#### What does `has_fpr: null` mean?

The document was delivered but the Item 19 section could not be located or parsed — see `item19_status` for the reason. `null` means **unknown**, deliberately distinct from `false` ("the section was found and the franchisor declines to make an FPR"). Treat `null` records as "read the PDF yourself", not as "no earnings claim".

#### Which FDD does it pick when a franchise has several filings?

The newest **complete** disclosure document: Clean FDD, Final FDD, or Revised FDD - Clean, newest filing year first. Redlines (Marked FDD, Revised FDD - Marked Up) may contain only the changed pages, so one is returned only when no complete document exists at all.

#### What is a "complex table" flag?

Some franchisors (e.g. Anytime Fitness) publish Item 19 as a multi-column quartile grid. Reconstructing every cell's column with text extraction alone is unreliable, so the actor flags these (`complex_table_flag: true`) and returns the raw text and all dollar figures rather than guessing a headline number.

#### How accurate is `headline_auv`?

It is extracted only when a single clean summary row is present (count + average + median + high + low), verified against the table header's column order. For complex/quartile tables it returns all-null and sets `complex_table_flag`.

### Pricing

**$0.60 per parsed FDD** — versus ~$220 per single-FDD report at FRANdata or $167/month at Franchimp. The parsed-Item-19 layer as structured data, for cents on their dollar, with cleaner provenance.

This actor is billed **per result** (per FDD record returned). One downloaded FDD PDF is exactly one billed record, so `maxFdds` — a single global budget across all names — is a hard cost cap. Only genuine full-FDD document types are ever downloaded, so you are never charged for an amendment or a deficiency notice. No document is billed twice within a run, whether two names resolve to the same document or the same name is listed twice. Failed searches/downloads are never billed and never consume the cap: diagnostics go to the run log and status message, not the dataset.

A record with `item19_status` other than `extracted` (rare — unusual layout, scanned image, parse error) is still one billed result: the FDD was found, downloaded and delivered with its full registration metadata and PDF link, and `has_fpr` is honestly `null` rather than a guessed `false`.

### Notes on the source

- **Minnesota CARDS** (`cards.web.commerce.state.mn.us`) — search + 500-row pages + stable per-document PDF URLs. Full filing history. Franchise names match by substring.
- The actor honors polite request delays and never attempts CAPTCHA or WAF evasion; a blocked source is reported, not bypassed.

# Actor input Schema

## `franchiseNames` (type: `array`):

One or more franchise or franchisor names to search for in the Minnesota CARDS registry (e.g. 'Jersey Mike's', 'Anytime Fitness'). Each name normally produces ONE record: the newest full FDD is downloaded and its Item 19 section parsed. CARDS matches franchise names by SUBSTRING, so a short string can match several franchisors. No document is billed twice in a run: repeated or whitespace-variant entries are collapsed before searching, and if two different names resolve to the same document it is delivered (and charged) once, with an unbilled log note naming the record that covers the other name. A name that returns nothing, that matches only non-FDD paperwork, or that is never reached because the maxFdds budget ran out also produces an unbilled log note, so no requested name ever disappears without explanation. Leave empty to use sweep mode (year + document type). You are billed per record returned, so maxFdds caps the cost.

## `year` (type: `string`):

Sweep mode: pull a batch of FDDs filed in this year (e.g. '2026') instead of by name. Combine with documentType to narrow (e.g. all 'Clean FDD' filed in 2026). When combined with franchiseNames, restricts each name's results to that filing year. Sweep mode downloads only genuine full FDD document types; if a sweep matches rows but none of them is an FDD, nothing is downloaded or billed and an unbilled diagnostic explains why.

## `documentType` (type: `string`):

Restrict to a Minnesota CARDS document type. 'Clean FDD' (the default when unset) is the standard full disclosure document and the best choice for Item 19 extraction. Choose 'Any document type' to apply no filter — the actor still downloads only full FDD document types (Clean, Final, Revised or Marked FDD) and never bills an amendment, consent or deficiency notice as an FDD. Applies to both name search and sweep mode.

## `states` (type: `array`):

Which state franchise registry to query. Minnesota CARDS is the source in this version: it offers full search, complete filing history, year sweeps and stable per-document PDF URLs, and because an FDD is a single national document most franchisors' disclosure documents are available there. 'MN' is the only supported value; support for a second registry (Wisconsin DFI) is planned for a later version. California and NASAA EFD are intentionally excluded because they block automated HTTP access.

## `maxFdds` (type: `integer`):

Hard cap on the number of FDD PDFs downloaded and parsed per run — a single global budget across all names. One downloaded PDF produces exactly one dataset record, so each parsed FDD is one billed result and this cap is also your hard cost cap. No document is downloaded or billed twice in a run (Minnesota documents are deduplicated by CARDS document id across every name you request). Failed searches/downloads are never written to the dataset (they are reported in the run log and status message) and do NOT consume it either. If the budget runs out before every requested name is searched, each unsearched name is named in the run log with the value to raise this to. FDDs are large (5-7 MB, 400-500 pages) and PDF text extraction is CPU-bound, so budget roughly 20-40 seconds per FDD at the default 4 GB memory. The default of 3 keeps a first run quick; raise it (up to 200) for batch sweeps and raise the run timeout to match.

## `downloadPdfToKvs` (type: `boolean`):

Also store each downloaded FDD PDF in the run's default key-value store (key returned as pdf\_bytes\_kvs\_key). Turn on if you want the raw PDF, not just the extracted Item 19 fields. Adds storage but does not change per-result billing.

## `requestDelaySeconds` (type: `integer`):

Politeness delay between HTTP requests to Minnesota CARDS. These are public government records with no published rate limit; 1-2 seconds is courteous. Lower values run faster but are less polite.

## `proxyConfiguration` (type: `object`):

Proxies for the HTTP requests. Minnesota CARDS is a public state-government site, so Apify Proxy (datacenter) is sufficient. Leave default unless the source rate-limits your IP.

## Actor input object example

```json
{
  "franchiseNames": [
    "Jersey Mike's"
  ],
  "documentType": "Clean FDD",
  "states": [
    "MN"
  ],
  "maxFdds": 3,
  "downloadPdfToKvs": false,
  "requestDelaySeconds": 2,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "franchiseNames": [
        "Jersey Mike's"
    ],
    "states": [
        "MN"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("silentshadow55/fdd-item19-actor").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 = {
    "franchiseNames": ["Jersey Mike's"],
    "states": ["MN"],
}

# Run the Actor and wait for it to finish
run = client.actor("silentshadow55/fdd-item19-actor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "franchiseNames": [
    "Jersey Mike'\''s"
  ],
  "states": [
    "MN"
  ]
}' |
apify call silentshadow55/fdd-item19-actor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=silentshadow55/fdd-item19-actor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "FDD Item 19 Parser — Franchise AUV & Financial Performance",
        "description": "Search state franchise registries (Minnesota CARDS + Wisconsin DFI), download Franchise Disclosure Document PDFs, and extract Item 19 Financial Performance Representations — has-FPR flag, raw Item 19 text, every dollar figure, and best-effort average/median/high/low unit volume. No logins.",
        "version": "0.0",
        "x-build-id": "0wxOjGyORK68Ka89E"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/silentshadow55~fdd-item19-actor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-silentshadow55-fdd-item19-actor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/silentshadow55~fdd-item19-actor/runs": {
            "post": {
                "operationId": "runs-sync-silentshadow55-fdd-item19-actor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/silentshadow55~fdd-item19-actor/run-sync": {
            "post": {
                "operationId": "run-sync-silentshadow55-fdd-item19-actor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "franchiseNames": {
                        "title": "Franchise names",
                        "type": "array",
                        "description": "One or more franchise or franchisor names to search for in the Minnesota CARDS registry (e.g. 'Jersey Mike's', 'Anytime Fitness'). Each name normally produces ONE record: the newest full FDD is downloaded and its Item 19 section parsed. CARDS matches franchise names by SUBSTRING, so a short string can match several franchisors. No document is billed twice in a run: repeated or whitespace-variant entries are collapsed before searching, and if two different names resolve to the same document it is delivered (and charged) once, with an unbilled log note naming the record that covers the other name. A name that returns nothing, that matches only non-FDD paperwork, or that is never reached because the maxFdds budget ran out also produces an unbilled log note, so no requested name ever disappears without explanation. Leave empty to use sweep mode (year + document type). You are billed per record returned, so maxFdds caps the cost.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "year": {
                        "title": "Filing year (sweep mode)",
                        "type": "string",
                        "description": "Sweep mode: pull a batch of FDDs filed in this year (e.g. '2026') instead of by name. Combine with documentType to narrow (e.g. all 'Clean FDD' filed in 2026). When combined with franchiseNames, restricts each name's results to that filing year. Sweep mode downloads only genuine full FDD document types; if a sweep matches rows but none of them is an FDD, nothing is downloaded or billed and an unbilled diagnostic explains why."
                    },
                    "documentType": {
                        "title": "Document type",
                        "enum": [
                            "",
                            "Clean FDD",
                            "Final FDD",
                            "Marked FDD",
                            "Revised FDD - Clean"
                        ],
                        "type": "string",
                        "description": "Restrict to a Minnesota CARDS document type. 'Clean FDD' (the default when unset) is the standard full disclosure document and the best choice for Item 19 extraction. Choose 'Any document type' to apply no filter — the actor still downloads only full FDD document types (Clean, Final, Revised or Marked FDD) and never bills an amendment, consent or deficiency notice as an FDD. Applies to both name search and sweep mode.",
                        "default": "Clean FDD"
                    },
                    "states": {
                        "title": "States",
                        "type": "array",
                        "description": "Which state franchise registry to query. Minnesota CARDS is the source in this version: it offers full search, complete filing history, year sweeps and stable per-document PDF URLs, and because an FDD is a single national document most franchisors' disclosure documents are available there. 'MN' is the only supported value; support for a second registry (Wisconsin DFI) is planned for a later version. California and NASAA EFD are intentionally excluded because they block automated HTTP access.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "MN"
                            ],
                            "enumTitles": [
                                "Minnesota — CARDS (search, filing history, FDD PDFs)"
                            ]
                        },
                        "default": [
                            "MN"
                        ]
                    },
                    "maxFdds": {
                        "title": "Max FDDs",
                        "minimum": 1,
                        "maximum": 200,
                        "type": "integer",
                        "description": "Hard cap on the number of FDD PDFs downloaded and parsed per run — a single global budget across all names. One downloaded PDF produces exactly one dataset record, so each parsed FDD is one billed result and this cap is also your hard cost cap. No document is downloaded or billed twice in a run (Minnesota documents are deduplicated by CARDS document id across every name you request). Failed searches/downloads are never written to the dataset (they are reported in the run log and status message) and do NOT consume it either. If the budget runs out before every requested name is searched, each unsearched name is named in the run log with the value to raise this to. FDDs are large (5-7 MB, 400-500 pages) and PDF text extraction is CPU-bound, so budget roughly 20-40 seconds per FDD at the default 4 GB memory. The default of 3 keeps a first run quick; raise it (up to 200) for batch sweeps and raise the run timeout to match.",
                        "default": 3
                    },
                    "downloadPdfToKvs": {
                        "title": "Save FDD PDFs to key-value store",
                        "type": "boolean",
                        "description": "Also store each downloaded FDD PDF in the run's default key-value store (key returned as pdf_bytes_kvs_key). Turn on if you want the raw PDF, not just the extracted Item 19 fields. Adds storage but does not change per-result billing.",
                        "default": false
                    },
                    "requestDelaySeconds": {
                        "title": "Delay between requests (seconds)",
                        "minimum": 0,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Politeness delay between HTTP requests to Minnesota CARDS. These are public government records with no published rate limit; 1-2 seconds is courteous. Lower values run faster but are less polite.",
                        "default": 2
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Proxies for the HTTP requests. Minnesota CARDS is a public state-government site, so Apify Proxy (datacenter) is sufficient. Leave default unless the source rate-limits your IP.",
                        "default": {
                            "useApifyProxy": true
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
