---
title: "Resolve Addresses Batch For Project"
method: POST
path: "/api/v1/project/{project_id}/address/resolve-many"
tags: ["project"]
---

# Resolve Addresses Batch For Project

`POST /api/v1/project/{project_id}/address/resolve-many`

Project-scoped batch resolve for both in-project surfaces — the import
dialog (Door 2) and chat paste.

The county scope is the project's canonical ``county_fips`` (derived
server-side, never client-supplied), so a paste can't resolve outside the
project's county; a project with no county scope is a 404. Resolution runs
against the project's sandbox — internal misses fall through to the forward
geocoder (it resolves points against a project) instead of classifying as
``not_in_dataset`` like the pre-project batch must.

## Request body

- ProjectAddressResolveManyRequest — Batch resolve inside an existing project — chat paste and the Door 2 import review. The county is not sent — it's derived server-side from the project's canonical ``county_fips`` (the client stays county-agnostic; deriving it from the boundary layer relation is the anti-pattern this avoids). Shares ``ADDRESS_ROW_CAP`` with the pre-project request for the reason stated there: the import dialog resolves through this route, so the two caps are one cap.
  - `queries` string[], required

## Response `200`

Successful Response

- AddressResolveManyResponse — Per-row outcomes for a pasted batch, one row per input in input order.
  - `rows` BatchResolutionRow[], required
    - `index` integer, required
    - `query` string, required
    - `kind` 'matched' | 'ambiguous' | 'not_in_dataset' | 'empty_input', required — Per-row bucket for a batch resolve, derived from a single row's ``ResolutionResult`` plus its raw input. Coarser than the single-address ``ResolutionOutcome``: it splits ``matched`` by CARDINALITY (one candidate vs. several) and distinguishes a blank input row, so a caller can route each row (seed / disambiguate / report-missing / flag-blank) without re-deriving. The accept/reject verdict on candidates still lives with the agent / human — this is a count, not a confidence threshold.
    - `candidates` AddressCandidate[], required
      - `source_table` 'parcel' | 'building' | 'place' | 'address' | 'school', required — The table a resolved feature lives in — what a caller pulls its data from, and the feature's kind. A text match in the ``address``, ``place`` or ``school`` table resolves (point-in-feature) to a ``parcel``/``building``; a ``parcel`` attribute match resolves to the parcel itself.
      - `feature_id` string, required
      - `label` string, required
      - `similarity` number, nullable
      - `matched_via` string, required
      - `county_fips` string, nullable

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/maia-analytics/apis/maia-api.md) · [All operations](https://skmtc.net/maia-analytics/apis/maia-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/maia-analytics/maia-api/versions/c5094ff58a23/schema)
