> ## 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.

# GET /v1/field-requests/{request_id}

> Poll a field request: status, queue position, the promised ETA, and — once the field is live — the resume call that answers your original ask.

## Poll first — your session will be dead when this completes

A new-field build takes hours, not seconds. The agent (or session) that filed
the request is almost certainly gone by the time the field is live, so the
contract is built around resumption:

1. On `accepted_new`, **store the `request_id` and the `resume` call in
   durable task state** — not in conversation context.
2. Poll this endpoint whenever a successor picks the task up. The poll state
   is the source of truth: it is always right, and it works even if every
   callback failed.
3. When `status` is `live`, execute the stored `resume` call (or re-read it
   from this response) — the exact `/v1/fetch` request that answers the
   original ask.

Webhook and email callbacks (below) are a convenience over polling, never a
second contract.

```bash theme={null}
curl -s https://api.mireye.com/v1/field-requests/fr_5d81c02e94aa4f31b7c6d2a90e8f1c3b \
  -H "Authorization: Bearer $MIREYE_API_TOKEN" | jq
```

```json theme={null}
{
  "request_id": "fr_5d81c02e94aa4f31b7c6d2a90e8f1c3b",
  "status": "building",
  "waiting_on": null,
  "phase": null,
  "queue_position": null,
  "estimated_ready_at": "2026-08-01T14:05:00+00:00",
  "resolved_locations": [
    { "index": 0, "resolved_location": { "lat": 30.199699, "lng": -97.496411, "source": "address" },
      "resolved_address": "480 Berdoll Ln, Cedar Creek, TX 78612" }
  ],
  "disposition": [ { "ask": "…", "disposition": "accepted_new", "field_id": "…",
                     "estimated_ready_at": "2026-08-01T14:05:00+00:00", "resume": { "…": "…" } } ],
  "resume": { "method": "POST", "url": "https://api.mireye.com/v1/fetch",
              "body": { "lat": 30.199699, "lng": -97.496411, "fields": ["…"] } },
  "context_blob": "{\"job\":\"site-screen-114\"}",
  "created_at": "2026-07-31T14:05:00+00:00",
  "updated_at": "2026-07-31T16:40:12+00:00"
}
```

Requests are visible only to the credential that filed them. An id that
doesn't exist — or belongs to someone else — is a
`404 field_request_not_found` either way, never a 403: a 403 would confirm
the id exists, which is a cross-tenant existence oracle over an enumerable
id space.

## Response fields

| Field                       | Type           | Notes                                                                                                                                                                                                                                                                 |
| --------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `request_id`                | string         | The id you filed.                                                                                                                                                                                                                                                     |
| `status`                    | string         | See the vocabulary below.                                                                                                                                                                                                                                             |
| `waiting_on`                | string or null | Who progress is blocked on, in your terms: `"requester"` (a confirm/clarify is waiting on you), `"operator"` (a human on our side has to look — e.g. screening failed and was parked rather than skipping dedup), or `null` (nobody — either done, or we're working). |
| `phase`                     | null           | Reserved for finer-grained build progress inside `building`; currently always `null` on this surface.                                                                                                                                                                 |
| `queue_position`            | number or null | Position in the build queue while a build ticket is open. Builds are single-flight, so it is real.                                                                                                                                                                    |
| `estimated_ready_at`        | string or null | The promise that was **made at acceptance**, read back verbatim — never recomputed on poll. An ETA that slides forward every time you look is not an ETA.                                                                                                             |
| `resolved_locations`        | array          | Your example locations as resolved (the `{lat, lng, source}` echo, plus `resolved_address` for address inputs).                                                                                                                                                       |
| `disposition`               | array          | The per-sub-ask screening outcome, unchanged from the POST response — see [the disposition reference](/api-reference/field-requests#the-response-one-disposition-per-sub-ask).                                                                                        |
| `resume`                    | object or null | The first resume call found in `disposition` — the `/v1/fetch` request that answers the ask.                                                                                                                                                                          |
| `context_blob`              | string or null | Your blob, byte-identical (first write wins across idempotent replays).                                                                                                                                                                                               |
| `created_at` / `updated_at` | string         | ISO-8601.                                                                                                                                                                                                                                                             |

## Status vocabulary

The full set, in lifecycle order. Intake outcomes first:

| `status`           | Meaning                                                                                                                                                             | What to do                                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `received`         | Filed and durable; screening hasn't finished (the [202 path](/api-reference/field-requests#when-screening-cant-finish-in-time-202)).                                | Poll; the disposition lands here.                                                                              |
| `screening`        | Being screened asynchronously. If `waiting_on` is `"operator"`, screening failed and a human has to look — it is parked rather than queueing a build without dedup. | Poll.                                                                                                          |
| `matched`          | The catalog already answers it — the value and resume call are in `disposition`.                                                                                    | Use the `resume` call. Done.                                                                                   |
| `awaiting_confirm` | A near-miss or clarify is waiting on you (`waiting_on: "requester"`). Nothing is built on ambiguity.                                                                | Accept the near-miss (use its `resume`), or re-POST with the candidate excluded via `constraints.must_not_be`. |
| `rejected`         | Every sub-ask was refused — typed codes and routing hints in `disposition`. Terminal.                                                                               | Follow the routing hint.                                                                                       |
| `queued`           | Accepted; a build ticket exists. `queue_position` and `estimated_ready_at` are live.                                                                                | Store the id, poll later.                                                                                      |

Build lifecycle, once queued (each transition appears here as it happens):

| `status`     | Meaning                                                                                                                                                                  |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `claimed`    | A build runner holds the ticket (usually passes straight to `building`).                                                                                                 |
| `building`   | The build is running: source research, contract authoring, implementation, a frozen truth eval — your `example_locations` (and any `claimed_value`) seed its eval cases. |
| `in_review`  | Built; in human review. Every new field is reviewed before it ships.                                                                                                     |
| `approved`   | Review passed; publish is being triggered.                                                                                                                               |
| `publishing` | Code/data are rolling out. The request does not go `live` on "the PR merged" or "the publish command exited 0" — only on the check that matters (next row).              |
| `live`       | **Prod `/v1/fetch` returned a real, cited, non-null value at your own example locations.** The `resume` call works now. Terminal.                                        |
| `blocked`    | An honest no, at whatever stage it became true. Terminal — see below.                                                                                                    |
| `expired`    | Reserved for a confirm window lapsing on an `awaiting_confirm` request. Terminal.                                                                                        |

Terminal set: `live`, `blocked`, `expired`, `rejected` (and `matched`, which
is answered rather than terminal-by-refusal). Everything else is in motion —
poll at whatever cadence your task runs on (builds move on a scale of hours;
your plan's normal request-per-minute limit is the only constraint).

## The three build outcomes

A finished build lands in one of three terminal outcomes. On the poll surface
they appear as `live` or `blocked`; the callbacks (below) carry the finer
`status` distinction:

* **`DONE`** → `live`, callback `event_type: "request_live"`. The field
  passed its eval cleanly.
* **`SHIP_LOW_CONFIDENCE`** → `live`, callback
  `event_type: "request_live_low_confidence"`. The field is live **with an
  honest, stated limit** — the `caveat` field in the callback. This is not a
  lesser approval: the caveat travels with the value, worded so an agent can
  propagate it into its own citations. If you consume the field, repeat the
  caveat wherever you cite the number.
* **`BLOCKED`** → `blocked`, callback `event_type: "request_blocked"`, with a
  typed `blocked_reason.code`, an explanation, and — where one exists — a
  `counter_offer` naming the nearest thing that *is* possible. The typed
  codes: `no_indexable_source`, `licensing`, `coverage_gap`,
  `quality_below_bar` (we built it and the eval says it would mislead),
  `realtime_only`, `cost_prohibitive`, `upstream_dead`, `pr_closed` (built,
  but declined in review), `other`.

The poll response does not currently carry the blocked reason or the caveat —
they arrive on the callback channels. If you poll only and see `blocked`, the
reason was also emailed/webhooked to the callback you registered (a callback
can be added after filing: re-POST the identical body with the same
`idempotency_key` and a `callback` — a present callback replaces the stored
one).

## Webhook callbacks

If you registered `callback.webhook_url`, each event is POSTed to it as JSON.
Headers:

| Header              | Value                                                                                                                        |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `X-Mireye-Event`    | The event type (`screening_completed`, `request_live`, `request_live_low_confidence`, `request_blocked`).                    |
| `X-Mireye-Delivery` | `<request_id>:<event_type>` — your dedup key. Delivery is **at-least-once**; drop a delivery key you have already processed. |
| `Content-Type`      | `application/json`                                                                                                           |

`screening_completed` fires when screening settles (useful mainly on the 202
path) and carries `{request_id, status, disposition}` — the same disposition
array the poll shows.

Completion events carry the machine-readable document:

```json theme={null}
{
  "request_id": "fr_5d81c02e94aa4f31b7c6d2a90e8f1c3b",
  "event_type": "request_live_low_confidence",
  "status": "SHIP_LOW_CONFIDENCE",
  "field_id": "state_highway_aadt",
  "fetch": {
    "method": "POST",
    "url": "https://api.mireye.com/v1/fetch",
    "body": { "lat": 30.199699, "lng": -97.496411, "fields": ["state_highway_aadt"] }
  },
  "value": 4300,
  "unit": "vehicles/day",
  "citation": "TxDOT Traffic Count Database, 2025 annual counts",
  "confidence": "medium",
  "caveat": "Count stations are sparse outside metro counties; values more than 2 miles from a station are interpolated along the route.",
  "context_blob": "{\"job\":\"site-screen-114\"}"
}
```

* `value`/`unit`/`citation` are the resolved value **at your original example
  location** — a value you can check beats a field id you have to go fetch to
  believe.
* `caveat` is present even when `null`: an explicit null says "we checked,
  there isn't one," so a consumer branching on key-presence never mistakes a
  clean DONE for an un-inspected one.
* `request_blocked` adds a `blocked_reason` object:
  `{"code": "coverage_gap", "explanation": "...", "counter_offer": "..."}`.
* Webhook URLs must resolve to a public address (private, loopback, and
  link-local targets are refused). Deliveries are retried on failure with
  backoff; the poll state stays correct regardless of delivery outcome.
* Webhooks are unsigned in V1 — the body contains only what you already know
  plus the result. Treat the payload as untrusted input to your own pipeline
  and verify via the poll endpoint if it matters.

## Email callbacks

If you registered `callback.email`, completion mail is written for a human
**and ends with the same machine-readable document in a fenced JSON block**,
so the recipient can be an agent without asking it to parse prose:

````text theme={null}
state_highway_aadt is live, with one limit on it.

At 30.199699, -97.496411: 4300 vehicles/day
Source: TxDOT Traffic Count Database, 2025 annual counts

The limit: Count stations are sparse outside metro counties; values more
than 2 miles from a station are interpolated along the route.
It travels with the value — repeat it wherever you cite the number.

Fetch it:
  POST https://api.mireye.com/v1/fetch
  {"lat": 30.199699, "lng": -97.496411, "fields": ["state_highway_aadt"]}

Everything above, including the caveat, machine-readable:

```json
{ "request_id": "fr_5d81c02e94aa4f31b7c6d2a90e8f1c3b", "event_type": "request_live_low_confidence", ... }
```

— Mireye
````

The fenced block is byte-equivalent to the webhook body — one document, two
channels, so an agent reading the email and an agent receiving the webhook
act on the same keys.

## Errors

| Error code                   | HTTP | Meaning                                                                            |
| ---------------------------- | ---- | ---------------------------------------------------------------------------------- |
| `field_request_not_found`    | 404  | No such request under your credential — including someone else's id (never a 403). |
| `field_requests_unavailable` | 503  | The request store is unreachable. Retry with backoff.                              |

## What we keep

Same policy as [the POST page](/api-reference/field-requests#what-we-keep):
address strings from `example_locations` are scrubbed 30 days after the
request reaches a terminal state; resolved coordinates and geocode metadata
are kept. Poll responses remain available after the scrub — only the address
text is removed.


## OpenAPI

````yaml GET /v1/field-requests/{request_id}
openapi: 3.1.0
info:
  title: Mireye Earth
  description: >-
    Provenance-tagged geospatial data for US coordinates. POST /v1/fetch for
    deterministic field values (POST /v1/fetch/batch for up to 25 locations at
    once); POST /v1/ask for natural-language Q&A; GET /v1/meta/fields for the
    catalog.
  version: 0.14.0
servers: []
security: []
paths:
  /v1/field-requests/{request_id}:
    get:
      tags:
        - field-requests
      summary: Get Field Request
      operationId: get_field_request_v1_field_requests__request_id__get
      parameters:
        - name: request_id
          in: path
          required: true
          schema:
            type: string
            title: Request Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Get Field Request V1 Field Requests  Request Id  Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError

````