> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mireye.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Find and enrich a parcel

> Run a one-result Search, choose cited enrichment, and review parcel identity before combining results.

Use Search to discover parcels that satisfy hard conditions. Use inline enrichment
when you want cited fields for those exact matches, or standalone Enrich when you
have one location to investigate. This walkthrough returns at most one parcel per
Search request and makes each optional paid step explicit. It does not guarantee
that the example area currently contains a match.

## Before the first request

Create an API key and accept current terms as described in
[Authentication](/authentication). Search and Enrich require the corresponding
licensed credential grants. Set `MIREYE_API_KEY` in your environment; the examples
use `curl`, `jq` and `uuidgen`. Never put a credential in a URL or a shared response file.

On Free, a completed Search query costs \$0.20, including a zero-match, limited or
partial result. Successful enrichment costs \$0.02 per delivered parcel. The ceilings
below cover these rates; active-plan discounts can lower the charge. Read the
returned `billing` receipt and [Pricing](/pricing) for the account's rates.
Running all three requests below has a combined ceiling of \$0.44. You can skip
the ordinary Search when choosing inline enrichment, or skip inline enrichment
when you only want to investigate one selected result separately.

Each new paid operation gets a new idempotency key. Keep that key **and the exact
request body** when recovering a lost response. The commands have no automatic
retry or pagination loop. Search and its inline enrichment share a 180-second
server budget; allow at least 210 seconds in the HTTP client or MCP host.

Choose names from the reference for the operation you are performing:

| Selection | Authoritative reference |
| - | - |
| Search hard filters, their types and units | [Search filters](/api-reference/search-fields) |
| Basic Search extras, full inline enrichment, or standalone Enrich fields | [Enrich fields and presets](/api-reference/enrich-fields) |
| Free Fetch fields and presets | [Fetch catalog](/api-reference/field-catalog), also `/v1/meta/fields` and `mireye://catalog/fields` |

The Fetch catalog is not the complete Search or Enrich catalog. Search's `apn`
filter corresponds to the Enrich output `parcelnumb`; `state` corresponds to `state2`.
Preserve APN punctuation and leading zeros, and retain state/county context.

## 1. Find one candidate

Create `search-request.json`:

```json theme={null}
{
  "filters": [
    {"field": "state", "op": "eq", "value": "AZ"},
    {"field": "county", "op": "eq", "value": "04013"},
    {"field": "acreage", "op": "between", "value": [100, 1000]}
  ],
  "limit": 1,
  "max_cost_usd": "0.20"
}
```

All filters must pass. Every Search needs a positive `state` or `state2` selection:
`eq` with one two-letter code, or `in` with a nonempty list from the 50 states and
DC. A county, APN or polygon filter does not replace it. For example, an APN in
Maricopa County still needs `state = AZ` and county `04013`; a polygon around Austin
still needs `state = TX`. GeoJSON positions use `[longitude, latitude]`.

Generate a key once for this operation, then send the request:

```bash theme={null}
export SEARCH_OPERATION_KEY="$(uuidgen)"
(
  if curl --silent --show-error --fail-with-body --max-time 210 \
    https://api.mireye.com/v1/search \
    -H "X-API-Key: $MIREYE_API_KEY" \
    -H "Idempotency-Key: $SEARCH_OPERATION_KEY" \
    -H 'Content-Type: application/json' \
    --data-binary @search-request.json > search-result.json; then
    jq '{status, completion_reason, request_id, next_cursor, matches, billing}' search-result.json
  else
    cat search-result.json >&2
    exit 1
  fi
)
```

Basic Search returns parcel identity, the stored parcel `analysis_point`, and scalar
filter values under `fields` unless already represented at the top level. Here the
county FIPS is returned as `fields.geoid`, separately from the county name. Add public
Search or Enrich names in `fields` for other values at the same query price.
The first match found is not a ranked recommendation. `limit: 1` bounds the
returned count, not the number of candidates that may need evaluation.

Inspect `status` and `completion_reason` before deciding what to do next:

* `complete` with `exhausted` means the loaded candidate set was exhausted, not
  that the source covers every real-world parcel.
* `limited` means the page limit or an internal work ceiling stopped the search.
* `partial` means some work failed or timed out. Keep confirmed matches; an empty
  partial page does not prove that no qualifying parcels exist.

Do not weaken the user's hard conditions to manufacture a match. If there is no
candidate to review, stop here or explicitly revise the request as a new operation.

## 2. Optionally enrich the shortlist inline

For the complete current Enrich catalog on each returned parcel, create
`search-enriched-request.json`:

```json theme={null}
{
  "filters": [
    {"field": "state", "op": "eq", "value": "AZ"},
    {"field": "county", "op": "eq", "value": "04013"},
    {"field": "acreage", "op": "between", "value": [100, 1000]}
  ],
  "enrich": true,
  "limit": 1,
  "max_cost_usd": "0.22"
}
```

This is a new Search operation, not an upgrade to the saved first response. Use a
new key and no old cursor. If you already know you need these fields, begin with
this request and skip the ordinary Search above. For only ownership and zoning, use
basic Search with `fields: ["owner", "zoning"]` instead.

```bash theme={null}
export SEARCH_ENRICH_OPERATION_KEY="$(uuidgen)"
(
  if curl --silent --show-error --fail-with-body --max-time 210 \
    https://api.mireye.com/v1/search \
    -H "X-API-Key: $MIREYE_API_KEY" \
    -H "Idempotency-Key: $SEARCH_ENRICH_OPERATION_KEY" \
    -H 'Content-Type: application/json' \
    --data-binary @search-enriched-request.json > search-enriched-result.json; then
    jq '{status, completion_reason, matches, billing}' search-enriched-result.json
  else
    cat search-enriched-result.json >&2
    exit 1
  fi
)
```

`enrich` must be a JSON boolean. With `enrich: true`, the entire current Enrich
catalog is attempted regardless of `fields`. Basic `fields` selections never enable
per-parcel enrichment billing.

Inline enrichment reuses the exact selected parcel and its stored parcel `lat`/`lon`
without another lookup. Each match contains `enriched_fields` instead of `fields`;
read `enriched_fields.owner.value`, for example. Check overall `status` and
`completion_reason`, then preserve each compact field's source, confidence, optional
unit and interpretation hints. The map can be sparse or empty even after a match.

Billing uses internal outcomes: at least one successful or valid no-data field counts
as one delivered enrichment, including partial work; invalid or all-failed enrichment
incurs no Enrich unit. No matches means no enrichment units. The public map's size
cannot determine the charge.

## 3. Optionally investigate one selected parcel separately

Standalone Enrich accepts exactly one locator: an address **or** both `lat` and
`lng`. It does not accept an APN or parcel ID as a locator. After reviewing the
one candidate in `search-result.json`, copy its actual `analysis_point` coordinates
into a small request. The following command refuses to continue without a usable
point and sends only `lat` and `lng`, not Search's `method` property:

```bash theme={null}
jq -e '
  .matches[0].analysis_point
  | select((.lat | type) == "number" and (.lng | type) == "number")
  | {lat, lng,
     fields: ["parcelnumb", "state2", "geoid", "owner", "elevation"],
     max_cost_usd: "0.02"}
' search-result.json > enrich-request.json &&
export ENRICH_OPERATION_KEY="$(uuidgen)" &&
curl --silent --show-error --fail-with-body --max-time 210 \
  https://api.mireye.com/v1/enrich \
  -H "X-API-Key: $MIREYE_API_KEY" \
  -H "Idempotency-Key: $ENRICH_OPERATION_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary @enrich-request.json > enrich-result.json
```

Keep the generated key and body to recover this operation; rerunning the whole
block generates a new key and can incur another charge. You can skip Search and
call Enrich directly when you already know the location.

Check `parcel_match.status` first. Only `matched` returns fields; `ambiguous`,
`no_match` and `unavailable` return an empty fields map. Do not choose an ambiguous
candidate automatically. Review `parcel_match.parcel`, `parcelnumb`, `state2` and
`geoid` against the selected Search result's APN, address, state/county and source.
Keep the two responses separate until the identity is resolved.

Basic Search can explicitly request supported identifiers such as `ll_uuid`,
but an identifier is not a standalone Enrich locator. Compare returned authoritative
identifiers when available. Matching APNs or nearby coordinates alone cannot prove
that both calls selected the same parcel. APNs can repeat across jurisdictions. Inline enrichment avoids
this second-match uncertainty when the goal is to enrich the Search match itself.

Standalone Enrich samples the matched parcel's stored centroid when available,
otherwise the input point (`stored_parcel_centroid` / `input_fallback`). Search
uses the unchanged stored parcel `lat`/`lon` with method `parcel_stored_lat_lon`, even
when that point is outside the polygon, so point-based values can differ even for
the same parcel. Search skips candidates with invalid stored coordinates and marks
the response partial. A point sample does not describe the whole boundary;
only fields explicitly defined as parcel calculations do that.

## Read returned values without losing their meaning

Enrich fields form a flat map in Enrich preset order; shared fields appear once,
followed by fields outside presets in catalog order. Preserve the returned order
when presenting or exporting a complete result.

Standalone Enrich, `mireye_enrich`, and Search `enriched_fields` use the same sparse
field projection. Each returned field
contains `value`, `source`, `confidence`, and `interpretation_hints`, plus `unit`
only when defined. Keep false and zero values. Failed fields are omitted, as are
null-valued fields outside a temporary 33-field allowlist. A retained null can
still mean a missing source attribute; do not assume it establishes absence.
Even a matched parcel can legitimately return `fields: {}`.

Standalone Enrich omits field `source_url` metadata, timestamps, vintage, TTL, notes,
field status, lifecycle and failure metadata, as well as top-level `fetched_at`
and `partial_failures`. Parcel identity, geocode quality, the analysis point,
`parcel_match.status` and billing remain available.

Search removes per-match `field_status`, `enrichment`, `enrichment_status` and
`enrichment_error`; it keeps one outer billing receipt and overall completion status.
Basic mode retains selected null values in `fields`. Full enrichment applies the
compact omission policy to `enriched_fields`. Neither a missing enriched key nor a
basic null is evidence of a negative finding. Fetch and Ask contracts are unchanged.

Standalone Enrich can combine `fields` with one `preset` by union. Omitting or
nulling both requests all 546 fields; an empty standalone `fields` list is invalid.
Enrich has no 50-field cap. This differs from both Search's empty-list behavior
and Fetch's explicit-field limit.

## Continue or recover deliberately

Only request another page when more results are needed and `next_cursor` is
non-null. Copy it as `cursor` while keeping filters, fields and `enrich` unchanged.
`limit` may change within 1–100. Each page is a new paid query with a new key and
its own cost ceiling. Cursors expire after one hour; changing enrichment mode or
selected fields requires restarting without the cursor.

| Situation | Next action |
| - | - |
| Lost response, disconnect, `operation_in_progress`, unknown billing outcome | Recover with the same key and identical payload, or read `/v1/operations/{operation_id}`. Respect any retry delay. |
| Saved partial result | Keep its successful evidence. Replaying it returns the saved result; it does not recompute failed fields. A deliberate new investigation is new paid work. |
| Known terminal operation failure | Correct the cause before starting a new operation with a new key. |
| `410 result_not_retained` | The work was charged but its result was not saved for replay. Keep the `receipt`; a new key runs the work again as a separately billed request. |
| Invalid filters or selectors | Correct the named issue using the operation's field reference; do not retry an unchanged invalid request. |
| Expired or request-mismatched cursor | Restart without the cursor and use a new key. |
| `409 dataset_changed` | Start a new operation without the old cursor after the dataset refresh. |
| `410 dataset_withdrawn` | Stop using that dataset/result; do not retry the withdrawn handle. |

A disconnected client does not cancel owned paid execution. Work keeps its
existing deadline, and saved results remain subject to current authorization,
dataset permissions and retention. Recovery does not add missing data or charge
again. Follow [Errors](/api-reference/errors) for
capacity, authorization and recovery details.

## Use the same workflow through hosted MCP

Connect through [hosted MCP](/mcp/installation). Send the same Search or Enrich
body inside `req`, with `idempotency_key` as its sibling. For example:

```json theme={null}
{
  "req": {
    "filters": [
      {"field": "state", "op": "eq", "value": "AZ"},
      {"field": "county", "op": "eq", "value": "04013"},
      {"field": "acreage", "op": "between", "value": [100, 1000]}
    ],
    "limit": 1,
    "max_cost_usd": "0.20"
  },
  "idempotency_key": "replace-with-one-new-operation-key"
}
```

Call `mireye_search` with this object. Use a unique key for new work and preserve
it for recovery; the displayed placeholder is not a reusable key for unrelated
queries. `mireye_enrich` uses the same wrapper for its locator and field selection.
The hosted client must allow at least 210 seconds for Search. OAuth credentials
belong to the MCP connection; do not substitute them for an HTTP API key.
