# Sonoma County Defaulted Property Taxes - Parcel, Balance Due (`j0401/sonoma-defaulted-tax`) Actor

Sonoma County (CA) defaulted secured property taxes (public open data, 9.8k tax-year rows / 6.8k parcels, daily): per-year total due and balance, redemption fees, five-year power-to-sell timeline, assessed value and exemptions. Filter by parcel, default year, amount, sale notice or status.

- **URL**: https://apify.com/j0401/sonoma-defaulted-tax.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Categories:** Business
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / 1,000 sonoma defaulted-tax 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

## Sonoma County Defaulted Property Taxes

Defaulted secured property-tax bills in Sonoma County, California - the step before a tax sale. One row per defaulted tax year of a parcel, from the county's public open data, refreshed daily (newest county update **9 November 2026**).

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold.**

### What you get

Each record is one defaulted tax year of one parcel:

- `assessmentNumber`, `feeparcel` - the assessment (parcel) number and the fee parcel it sits on (2,746 rows differ after a parcel split)
- `originatingAssessmentNumber` - the original assessment number when the parcel was split
- `taxYear`, `rollYear`, `taxRateArea` - tax-rate year, roll year and rate area
- `defaultNumber`, `defaultDate`, `billDate` - the county's default reference, default date and bill print date
- **`totalDue`** - base tax + 10% penalty + cost charge for that tax year
- **`balanceDue`** - `totalDue` minus what has been paid (never negative)
- `baseTaxAmount`, `penaltyAmount`, `costCharge`, `paidAmount`
- `defaultAmount` - the county's *first-year* default amount (see below)
- `amountBasis` - `components` when `totalDue` comes from the three components, `defaultAmount` on the 72 rows where all three are 0 and the county's default amount is the only figure available
- `redemptionFee`, `redemptionTotalFees`, `priorYearTaxesPaid`, `delinquencyInterestPaid`
- `redeemedDate`, `saleNoticeDate`, `status` - `outstanding` or `redeemed` (our derivation from the redemption date and amount paid; `mode="parcel"` can also say `mixed` when a parcel's tax years disagree)
- **`redemptionPeriodEnd`**, **`yearsInDefault`**, **`powerToSellRecorded`** - the California five-year power-to-sell timeline
- `netValue`, `agPreserve` - net assessed value and the agricultural-preserve flag
- `exemptionCode1` / `exemptionLabel1` / `exemptionAmount1` (and slot 2) - the county exemption, e.g. `E01` Homeowner
- `address`, `city` - the property's own location

### How the money reads

The county publishes one row per defaulted tax year, and the amount fields do not all mean the same thing:

- **`totalDue` is the figure to use per tax year.** It follows the county's own redemption formula (`base tax + 10% penalty + cost charge`); 1,913 of the 2,043 redeemed parcels (93.6%) have `paidAmount` equal to their summed `totalDue` as delivered (1,972 match if you sum only the three components - the difference is the fallback rows below).
- **95 rows have all three components at 0 while the county still records an amount** (72 of them non-zero, $782,473 in total across 72 parcels - large assessments whose tax detail was never broken out). On those, `totalDue` falls back to `defaultAmount` and `amountBasis` says `defaultAmount`. Without that fallback those parcels - including 68 whose every row has zero components - would read as owing nothing. The fallback applies to the single row that carries `defaultAmount`; the parcel's other zero-component tax-year rows still show `totalDue=0` in `rows` mode - use `mode="parcel"` for the parcel's combined amount.
- **`defaultAmount` exists on one row per parcel only** - the earliest tax year of the default. On the other tax-year rows of the same parcel it is `0`, and a `0` there does **not** mean "nothing is owed"; use `totalDue`.
- **A redeemed row can still carry a balance.** 81 rows have a partial payment (`0 < paidAmount < totalDue`), and 142 redeemed rows in total show `balanceDue > 0` (the remainder are fallback rows whose default amount exceeds what was paid, including rows with `paidAmount=0`). So `status="redeemed"` and `balanceDue > 0` can both be true. Use `minBalanceDue` to find money still owed rather than relying on `status` alone.
- **`redemptionTotalFees`, `priorYearTaxesPaid`, `redeemedDate` and `saleNoticeDate` are default-record values repeated on every tax-year row.** Do not sum them across rows. `defaultDate` is normally the same on every row of a parcel too, but two parcels in the current file carry more than one default date.
- **`taxYear` is the tax-rate year, not the default year.** A default recorded on 30 June 2026 can carry tax years 2023-2025; `taxYear="2026"` returns nothing.
- These are the county's redemption figures. They do not add the interest that keeps accruing, so they are not a title company's payoff quote.

### The five-year timeline

California lets the tax collector record a power to sell once a property is five years delinquent. The source's `saleNoticeDate` is exactly that event. We surface it three ways:

- `redemptionPeriodEnd` = `defaultDate` + 5 years (a statutory calculation, not a county promise)
- `yearsInDefault` = years since the default date
- `powerToSellRecorded` = `true` when a sale notice is on record, else `false`

**332 rows carry a sale notice; 242 of them are still outstanding.** Sale notices appear only on defaults from 2014-2021 - consistent with the five-year rule.

### Examples

The 50 newest defaults:

```json
{ "mode": "rows", "maxResults": 50 }
```

One parcel - 13 defaulted tax years, outstanding, power to sell recorded:

```json
{ "mode": "parcel", "assessmentNumber": "095032008000" }
```

Still outstanding, at least $5,000 due in a single tax year:

```json
{ "status": "outstanding", "minTotalDue": 5000, "maxResults": 200 }
```

Money still owed (a partial payment leaves a balance even on a redeemed row):

```json
{ "minBalanceDue": 1000, "maxResults": 200 }
```

Defaulted tax-year rows where the county has recorded a power to sell
(332 rows across 80 parcels):

```json
{ "hasSaleNotice": true, "maxResults": 100 }
```

Homeowner-exemption rows:

```json
{ "exemptionCode": "E01", "maxResults": 100 }
```

Defaults from the 2024 delinquency year onward (every default date in the file is 30 June):

```json
{ "defaultYearFrom": "2024", "maxResults": 100 }
```

Defaults by tax year:

```json
{ "mode": "aggregate", "groupBy": "taxYear" }
```

Defaults by city:

```json
{ "mode": "aggregate", "groupBy": "city" }
```

### Coverage and honest limits

- **9,789 tax-year rows across 6,776 parcels** at build time. Rows are neither parcels nor bills: one parcel can carry up to 13 defaulted tax years.
- **7,321 rows outstanding** (4,733 parcels) and **2,468 rows redeemed** (2,043 parcels).
- **1,724 rows carry an exemption** in slot 1 (1,619 of them `E01` Homeowner). Unknown codes are returned with an empty label rather than a guess.
- The dataset is the county's *defaulted* list. It is not every delinquent bill in the county, and it does not include the full payoff quote a title company would compute.
- **No owner name is published** in this dataset. The owner's **mailing address is deliberately excluded** - only the property's own location is returned.
- `bankruptcy` and `taxability` are omitted: the source returns "No" / null on every row, and a column that never varies carries no information.
- The source's four "value split" columns (`billedmarketlandvalue`, `billedfixedimprvalue`, `billedgrowingimprvalue`, `billedstructuralimprvalue`) are identical **to each other on every one of the 9,789 rows**, so they are not a land/improvement breakdown and are not exposed; `netValue` is.
- 12 rows have no location address and 15 no city in the source; the city filter also cannot reach 20 rows whose combined field holds only `CA`. Address or city filters therefore skip 12 and 35 rows respectively.
- **`mode="parcel"` returns the parcel's rollup**: `defaultNumbers`, `firstDefaultDate`, `latestDefaultDate`, `taxYears`, `recordCount`, `totalBaseTax`, `totalPenalty`, `totalCost`, `totalDue`, `totalPaid` and `balanceDue` sum the parcel's tax years, while `defaultAmount` stays the first-year figure. The property fields (`address`, `netValue`, `exemption*`, `agPreserve`, `taxRateArea`) come from the parcel's most recent tax-year row - an exemption that existed only in an earlier year is not carried forward.
- A single run can deliver the whole file (9,789 rows; the cap is 10,000). Larger pulls are metered per record. When `maxResults` or the run-level charge cap stops a query, the dataset also carries one unbilled `_meta` row with `truncated`, `delivered` (a lower bound when `stopReason="charge-limit"`), `totalMatched` and `stopReason`.
- Assessment numbers are 12 digits in the source; a leading zero dropped by a spreadsheet is restored, so `95032008000` and `095032008000` are the same parcel.
- The county refreshes daily. New defaults appear in a batch each July; redemptions update through the year. `sourceUpdatedAt` is the county's last update date.

### Related

Also available in this account: **NYC Tax Lien Sale Lists** (tax-lien sale notices with BBL, borough, block and lot) and **CA county business licenses** (Sonoma and Sacramento).

# Actor input Schema

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

rows = one defaulted tax year (default). aggregate = one count row per group (see groupBy). parcel = one assessment number rolled up: every defaulted tax year, totals and balance.

## `assessmentNumber` (type: `string`):

Exact Sonoma assessment (parcel) number, e.g. "117030022000". Required for mode=parcel.

## `defaultNumber` (type: `string`):

Exact default number, e.g. "DEF260001626". One default can cover several parcels and several tax years.

## `taxYear` (type: `string`):

Four-digit tax-RATE year, e.g. "2025". This is not the default year: a June 2026 default can carry tax years 2023-2025, and taxYear 2026 returns nothing.

## `address` (type: `string`):

Street-address prefix, case-insensitive (e.g. "1321 GAIL"). The owner's mailing address is deliberately not in this dataset.

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

City prefix, case-insensitive (e.g. "SEBASTOPOL").

## `status` (type: `string`):

outstanding = no redemption recorded and the amount paid is below the default amount. redeemed = a redemption date exists or the first-year default was paid in full.

## `minAmountDue` (type: `number`):

Only rows whose first-year default amount is at least this many dollars. That amount exists on one row per parcel; use minTotalDue for a per-tax-year amount.

## `minTotalDue` (type: `number`):

Only rows whose totalDue is at least this many dollars. totalDue is base tax + 10% penalty + cost charge; on the 95 rows where all three are 0 the county's defaultAmount is used instead (see amountBasis).

## `minBalanceDue` (type: `number`):

Only rows where totalDue minus amount paid is at least this many dollars. Use this to find money still owed - a redeemed row can still carry a balance after a partial payment.

## `minNetValue` (type: `number`):

Only rows whose net assessed value is at least this many dollars.

## `hasSaleNotice` (type: `boolean`):

true = the county has recorded a sale notice (power to sell) on the default; false = it has not.

## `defaultYearFrom` (type: `string`):

Four-digit default year - the 30 June delinquency year in the county's file - keeps that year or later, e.g. "2020".

## `defaultYearTo` (type: `string`):

Four-digit default year - the 30 June delinquency year - keeps that year or earlier.

## `exemptionCode` (type: `string`):

Exact county exemption code, e.g. "E01" (homeowner), "E99" (low value), "E22" (religious). Matches either exemption slot.

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

Dimension for mode=aggregate (blank = taxYear). Every group is returned.

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

Cap on records pushed in rows mode (0 = default 50; up to 10,000 per run - the whole file is 9,789). Each record is metered individually.

## Actor input object example

```json
{
  "mode": "",
  "status": "",
  "groupBy": "",
  "maxResults": 50
}
```

# Actor output Schema

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

Sonoma County defaulted-tax 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/sonoma-defaulted-tax").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/sonoma-defaulted-tax").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/sonoma-defaulted-tax --silent --output-dataset

```

## MCP server setup

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

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/MZEzWnfxVXgZpuNHX/builds/xj0SXfOFISML1f9uK/openapi.json
