# Maricopa County Property Sales - Assessor Affidavits (`j0401/maricopa-assessor`) Actor

Maricopa County (AZ) Assessor Sales Affidavits (899k parcels, free public data): the most recent recorded sale for every parcel - buyer and seller names, price, deed, property type, financing and the Assessor's own sale code. Search by owner, city, ZIP, price or date.

- **URL**: https://apify.com/j0401/maricopa-assessor.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / 1,000 maricopa county parcel sale records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Maricopa County Property Sales - Assessor Sales Affidavits

The Maricopa County Assessor publishes its **Sales Affidavits** dataset as free public data - the record of the **most recent recorded sale for every parcel** in the county, with the **buyer**, the **seller**, the **sale price** and the deed. This actor turns that register into a **charged-per-record lookup and screening tool**.

**Built for:** real-estate due diligence and market analysis - comparable-sales and price research, owner and title chain-of-title checks, foreclosure and related-party screening, investor and lender prospecting, absentee-owner identification, and county-level sale analysis.

### What it covers

**898,642 parcels** (the latest recorded sale per parcel, weekly refresh):

| Property type | Parcels |
|---|---|
| Single Family Residence | 651,589 |
| Condo / Townhouse | 95,267 |
| Vacant Land | 58,650 |
| Commercial / Industrial | 37,203 |
| Apartment Building | 15,540 |
| Other Use | 8,266 |
| Mobile / Manufactured | 4,363 |
| 2-4 Plex | 2,914 |
| Agricultural | 1,318 |

Every row carries the **parcel number**, the **sale date** and **sale price**, the **deed number / date / type**, the **property type**, the **situs address / city / ZIP**, the **buyer (grantee)** and **seller (grantor)** names with their mailing addresses and states, the **financing** (cash, conventional, FHA ), a **multi-parcel** indicator, a **related-party** (buyer-seller relationship) flag, and the **Assessor's own sale/quality code** - the Assessor's classification of the sale, e.g. foreclosure, court-ordered, out-of-state address, or a clean arm's-length sale.

> **Two things worth knowing.** Sale dates are **month-precise** in the source (`2026-01`, no day). And the Assessor's code is the county's own read on each sale: `X` (no reject or warning) 504,789 / `W1` (buyer or seller has an out-of-state address) 233,433 / `W16` (more than 5 parcels sold) 29,825 / `R97` **foreclosure sale** 25,656, plus 50 more codes - a genuine sale-quality facet no plain deed list carries.

### Typical questions

- "What did **this parcel** last sell for, and who bought and sold it?"
- "Show every **single-family home in Phoenix that sold for $500,000 or more**."
- "Did **this buyer or seller** appear in county sales?"
- "Find **related-party** sales - parent/child, common-ownership transfers."
- "Which sales were flagged **foreclosure** (Assessor code `R97`)?"
- "How are Maricopa property sales **distributed by city, year and price**?"

### Inputs

| Input | What it does |
|---|---|
| `parcelNumber` / `deedNumber` | exact parcel (APN) or deed number -> that sale |
| `name` / `grantorName` / `granteeName` | buyer or seller name substring, case-insensitive |
| `city` / `zipCode` | situs property location |
| `propertyType` / `deedType` / `financeType` | property classification / deed type / financing |
| `assessorCode` | the Assessor's sale/quality code (`X`, `W1`, `R97` ) |
| `saleFrom` / `saleTo` | sale month window (month precision - accepts `YYYY` or `YYYY-MM`) |
| `priceMin` / `priceMax` | sale price range (a price filter only returns sales that record a price) |
| `multiParcel` / `relatedParty` | multi-parcel sales / related-party transfers only |
| `aggregate` / `groupBy` | one summary row per group with a count - property type / deed type / city / year / financing / assessor code |
| `maxResults` | cap records (default 200) |

**Default run = a tiny aggregate** (property-type mix) - fast and safe for the daily auto-test, never a surprise full dump. For records, add a `city` / `granteeName` / `priceMin` filter or a `parcelNumber`.

### Example inputs

**Look up one parcel** - a bare parcel number returns its most recent recorded sale.

```json
{ "parcelNumber": "20904027B" }
```

**Phoenix single-family homes at $500,000 or more** -

```json
{ "city": "PHOENIX", "propertyType": "Single Family Reside", "priceMin": 500000, "maxResults": 10 }
```

**Foreclosure-coded sales** - the Assessor's `R97` code marks a foreclosure sale.

```json
{ "assessorCode": "R97", "maxResults": 10 }
```

**The property-type mix** - one summary row per property type, across the county.

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

### Low cost

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

Maricopa's register is a **61 MB zip holding a 256 MB flat text file** with no query server behind it - there is no way to ask the county for "just Phoenix single-family sales over $500k". Rather than make every lookup pay for a full-register download, the register is **mirrored weekly**, and each run queries the mirror in a single pass. That mirror is what lets an 898,642-parcel register behave like a live lookup at per-record pricing. Every pull is integrity-checked against the register's known shape (total count, the deed-type mix, the property-type vocabulary, key-column coverage), so a degraded or schema-changed source **fails loudly** instead of returning bad rows.

### Example output

**`parcelNumber=20904027B`** - a commercial sale, buyer and seller named:

```json
{
 "platform": "maricopa-assessor",
 "source": "maricopa-sales-affidavits",
 "state": "AZ",
 "county": "Maricopa",
 "parcelNumber": "20904027B",
 "saleDate": "2000-01",
 "saleYear": "2000",
 "salePrice": "210000",
 "deedNumber": "000000267",
 "deedDate": "2000-01-03",
 "deedType": "JC",
 "propertyTypeCode": "F",
 "propertyType": "Commercial/Industria",
 "situsAddress": "22026 N 24TH AVE",
 "situsSuite": "",
 "situsCity": "PHOENIX",
 "situsZip": "85027",
 "grantorName": "ROBBINS JEFFREY D/REBECCA M/ERIC C",
 "grantorAddress": "22684 N 93RD ST",
 "grantorCity": "SCOTTSDALE",
 "grantorState": "AZ",
 "grantorZip": "85255",
 "grantorCountry": "USA",
 "granteeName": "GRIM GARY L/CATHY J",
 "granteeAddress": "25411 N 11TH AVE",
 "granteeCity": "PHOENIX",
 "granteeState": "AZ",
 "granteeZip": "85027",
 "granteeCountry": "USA",
 "financeTypeCode": "",
 "financeType": "",
 "downPayment": "",
 "partialInterest": "N",
 "partialInterestPercent": "",
 "multiParcel": "Y",
 "numberOfParcels": "1",
 "buySellRelationship": "",
 "ownerOccupancy": "",
 "assessorCode": "X",
 "assessorCodeDescription": "ABSENCE OF REJECT/WARNING/EXEMPT CODE",
 "refreshed": "2026-10-07",
 "mode": "record",
 "groupKey": "",
 "groupCount": ""
}
```

**`aggregate=true`, `groupBy=situsCity`** - sales by city (top):

```
PHOENIX        229,598
MESA            99,759
SCOTTSDALE      70,685
GILBERT         49,858
```

### Source

- [Maricopa County Assessor - Data Downloads](https://mcassessor.maricopa.gov/page/data_sales/) - the official free public dataset this actor reads.
- Sale data is the Assessor's own published record; it reflects the county's record as of the weekly refresh.

# Actor input Schema

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

lookup = one parcel or deed number's sale(s). aggregate = one row per group. Leave blank to auto-route: a bare parcelNumber/deedNumber -> lookup, otherwise search (or aggregate when aggregate=true).

## `parcelNumber` (type: `string`):

Exact Maricopa Assessor parcel number (APN), e.g. "20904027B". Returns that parcel's most recent recorded sale.

## `deedNumber` (type: `string`):

Exact recorder deed number, e.g. "000000267" (leading zeros ignored). Returns the sale(s) recorded under that deed.

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

Matches either the buyer (grantee) or the seller (grantor) name, substring, case-insensitive.

## `grantorName` (type: `string`):

Seller / grantor name substring, case-insensitive (e.g. "CENTEX HOMES").

## `granteeName` (type: `string`):

Buyer / grantee name substring, case-insensitive.

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

Property city, substring, case-insensitive (e.g. "PHOENIX", "SCOTTSDALE").

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

Property ZIP prefix, digits only (e.g. "8525").

## `propertyType` (type: `string`):

The Assessor's property classification. (Descriptions are truncated to 20 characters by the source, hence "Single Family Reside".) You may also pass the one-letter code (B, C, A, F ).

## `deedType` (type: `string`):

Recorder deed type code, exact match (e.g. "WD" warranty deed, "SD" special warranty, "JC" joint tenancy, "JD", "PL").

## `financeType` (type: `string`):

How the sale was financed, exact match (e.g. "New Loan - Conventional", "Cash (100%)", "New Loan - FHA").

## `assessorCode` (type: `string`):

The Assessor's own sale/quality code, exact match. Examples: "X" (no reject/warning), "W1" (buyer or seller has an out-of-state address), "R97" (foreclosure sale), "R94" (court-ordered).

## `saleFrom` (type: `string`):

Earliest sale month (inclusive). Accepts "YYYY" or "YYYY-MM" or "M/YYYY". Sale dates are month-precise in the source.

## `saleTo` (type: `string`):

Latest sale month (inclusive). Accepts "YYYY" or "YYYY-MM" or "M/YYYY".

## `priceMin` (type: `number`):

Lowest sale price (USD). A price filter only returns sales that record a price.

## `priceMax` (type: `number`):

Highest sale price (USD).

## `multiParcel` (type: `boolean`):

true = only sales covering more than one parcel; false = only single-parcel sales; leave unset for all.

## `relatedParty` (type: `boolean`):

true = only sales where buyer and seller are related (parent/child, common ownership, siblings ); false = only unrelated; leave unset for all.

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

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

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

propertyType -> the property mix; situsCity -> city distribution; saleYear -> sales volume by year; assessorCode -> the Assessor's sale/quality mix.

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

Cap the number of records pushed (0 = a reasonable ceiling of 200).

## Actor input object example

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

# Actor output Schema

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

Maricopa County parcel sale records - as JSON

## `datasetUrl` (type: `string`):

No description

## `runUrl` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("j0401/maricopa-assessor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("j0401/maricopa-assessor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{}' |
apify call j0401/maricopa-assessor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,j0401/maricopa-assessor"
        }
    }
}
```

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/57uca9csfekxWfbyG/builds/quyYFOmpsY2I8FNsH/openapi.json
