Skip to main content
POST
Fetch fields for up to 25 locations in one request

When to use this

You have a list — candidate properties, a portfolio, a county’s worth of addresses — and you want the same screen over all of them. This is /v1/fetch applied to up to 25 locations in one request: one field selection, N locations, index-aligned results. If you have one location, use /v1/fetch. If your list is bigger than 25, page it — the bound exists so one request cannot stampede the ~84 upstream sources every location fans out to.

Request

Each entry in locations is the exact locator contract of /v1/fetch: lat+lng or address, never both. The field selection (fields and/or preset) is batch-wide by design — the batch exists for “the same screen over a list”, and per-location field lists would make the response shape unpredictable for exactly the clients (agents, spreadsheets) it serves.

Response

Three properties to build on:
  1. Results are index-aligned with the request. results[i] answers locations[i], always, and carries index explicitly so a filtered or logged entry stays attributable.
  2. Each ok: true entry is a /v1/fetch response body. Same fields shape, same tri-state field status, same partial_failures, same geocode echo when the location was an address. A client that parses the single endpoint parses the batch with no new code.
  3. A location’s failure is an entry, never an HTTP failure. Location #7’s bad address cannot cost you the other 24 results: it becomes {"ok": false, "error": {…}} with the same error object (error, message, retryable) the single endpoint would have returned for that location — one error-handling code path for both endpoints.

Two levels of partial failure

Don’t conflate them:
  • Entry-level (ok: false): the location itself failed — the address didn’t geocode, the coordinate is outside the US envelope, or the worker shed the location at capacity (fetch_busy, retryable).
  • Field-level (partial_failures inside an ok: true entry): the location was fine, but individual fields failed upstream — identical semantics to /v1/fetch.
A batch-level HTTP error is reserved for the caller’s own mistakes, which are identical for every location: unknown field names (400 fields_unknown), no fields (400 no_fields_requested), too many explicit fields (400 fields_too_many), an over-long list (422), or a malformed locator (422).

Limits

  • 25 locations maximum per request (422 above it).
  • The /v1/fetch field rules apply unchanged: 50 explicit fields max, presets exempt.
  • Locations are processed 4 at a time inside the batch, and every location counts against the same per-worker admission gate as a single /v1/fetch — a batch is 25 requests’ worth of work and is metered as such, not smuggled under one admission slot. A location shed at capacity returns as an ok: false fetch_busy entry (retryable) rather than failing the batch.
  • Worst-case latency ≈ 90 s (every location cold, every source at its budget). Typical is far lower, but set your client timeout to 120 s+, same guidance as /v1/ask.
  • Addresses bill one geocode lookup each (cache-served repeats are free, 30-day TTL), and metered sources (e.g. parcel lookups) bill per location — a 25-location batch with a parcel field is 25 metered calls.
  • Batch is REST-only for now: the MCP mireye_fetch tool stays single-location (agents iterate naturally), and MCP hosts impose their own tool-response size limits a 25-location payload would fight.

Retries and lost responses (Idempotency-Key)

Billing commits per location as it computes, and the response arrives as one JSON body at the end — so a response lost in transit (a gateway 502, a client read timeout) would otherwise mean paying for results you never received. The Idempotency-Key header closes that gap:
  • Shape: 8–128 characters of [A-Za-z0-9_-]. Use a fresh key per distinct batch (a run id, a UUID).
  • On a lost response, retry with the SAME key and the SAME body. If the original computation finished server-side, you get the already-computed result back at zero additional charge, marked "replayed": true. The stored result lives 24 hours.
  • 409 batch_in_progress (with Retry-After): your retry raced the original computation — it is still running server-side. Wait and retry with the same key; do not switch keys (that recomputes and re-bills).
  • 409 idempotency_key_reused: the key was already used with a different request body. Keys pin the exact batch they answered.
  • Replays are free of credit charges but still count against your per-minute rate limit — a replay is a request.
  • The header is optional; requests without it behave exactly as before.
For batches where you would rather not hold an HTTP connection at all, use POST /v1/runs (kind: fetch_batch) — submit, poll, and collect results; it survives disconnects by design.

Headers

Idempotency-Key
string | null

Body

application/json

N locations, one field selection.

The field selection is deliberately batch-wide, not per-location: the batch exists for "the same screen over a list of candidate properties", and per-location field lists would make the response shape unpredictable for exactly the clients (agents, spreadsheets) the batch serves.

locations
BatchFetchLocation · object[]
required
Required array length: 1 - 25 elements
fields
string[] | null
preset
enum<string> | null
Available options:
terrain,
flood_risk,
wildfire_underwrite,
land_cover,
site_selection,
building_lookup,
points_of_interest,
utilities,
boundaries,
solar_siting,
wind_siting,
storage_siting,
data_center_siting,
grid_interconnect,
natural_hazard

Response

Successful Response