---
title: "Get batch verification results."
method: GET
path: "/v1/requests/{id}/results"
---

# Get batch verification results.

`GET /v1/requests/{id}/results`

## Request

- Base URL: `https://api.bounceless.io`
- URL: `https://api.bounceless.io/v1/requests/{id}/results`
- Auth: API key in header `X-Api-Key`

Results are readable while processing. Prefer cursor pagination: start without cursor, then pass each non-null nextCursor unchanged. Keep collecting while countsMayChange is true; after the request becomes terminal, start one final cursor walk from the beginning and de-duplicate by email to obtain the settled snapshot. offset remains supported for compatibility but is not recommended. A malformed cursor returns 400. Optional state, resultCategory and q filters narrow the walk server-side before pagination; keep them unchanged while following nextCursor. state preserves the initial outcome; resultCategory groups completed catch-all resolutions into deliverable, undeliverable or risky. Unknown filter values or a q longer than 200 characters return 400.

## Path parameters

- `id` string, uuid, required

## Query parameters

- `limit` integer
- `cursor` string
- `offset` integer
- `state` string
- `resultCategory` string
- `q` string
- `order` 'asc' | 'desc'

## Response `200`

Paginated results.

- ResultsPage
  - `jobId` string, uuid, required
  - `results` ResultItem[], required
    - `email` string
    - `state` string
    - `resultCategory` 'deliverable' | 'catch_all' | 'unknown' | 'undeliverable' | 'risky' | 'recheck' | 'pending' | 'other'
    - `score` number, nullable
    - `subStatus` string, nullable
    - `reasonCodes` string[], nullable
    - `decision` object, nullable
    - `presend` object
    - `evidence` ControlEvidence[]: Optional per-check evidence (BL-11576). Present only for checks the engine actually reported; the key is omitted when none were. A missing check means unavailable, never pass. Never derived from the verdict.
      - `kind` 'format' | 'mx' | 'mailbox' | 'catch_all' | 'risk', required
      - `state` 'pass' | 'fail' | 'unknown' | 'not_run', required: Taken from the engine classification of that check (SMTP matched rule, catch-all reason), never the raw SMTP code class. unknown = ran, inconclusive (incl. greylist, or a block of our sending IP); not_run = engine attested it did not run; fail = ran with an unfavourable observation.
      - `reason` string, required: Stable machine token, e.g. rcpt_accepted, rcpt_rejected, mailbox_full, rcpt_inconclusive, probe_not_attempted, catch_all_detected, catch_all_ruled_out, catch_all_unconfirmed, list_match.
      - `observedAt` string, date-time, nullable, required: Engine observation instant (cycle attestation, else engine verified_at). null when the engine did not provide one.
      - `provenance` object, nullable, required
        - `mechanism` string, nullable, required
        - `mechanismRevision` string, required
        - `freshness` 'fresh_probe' | 'fresh_cache', required
      - `measurement` object: Allowlisted measurements (smtpCode, enhancedCode, probes, accepts, quorum, list).
    - `checks` Checks: Per-control checks (BL-11693, engine wire BL-11692). Always four keys. States are the engine's, passed through; a check the engine did not emit is {state:"unknown", reason_code:"evidence_unavailable"}. Never derived from the verdict.
      - `syntax` Check, required
        - `state` 'passed' | 'failed' | 'unknown' | 'not_run' | 'error', required
        - `reason_code` string, required: Machine token; evidence_unavailable when the engine emitted nothing usable.
        - `observed_at` string, date-time
        - `detail` string: Machine token only; free text is never forwarded.
      - `mail_records` Check, required
        - `state` 'passed' | 'failed' | 'unknown' | 'not_run' | 'error', required
        - `reason_code` string, required: Machine token; evidence_unavailable when the engine emitted nothing usable.
        - `observed_at` string, date-time
        - `detail` string: Machine token only; free text is never forwarded.
      - `mailbox` Check, required
        - `state` 'passed' | 'failed' | 'unknown' | 'not_run' | 'error', required
        - `reason_code` string, required: Machine token; evidence_unavailable when the engine emitted nothing usable.
        - `observed_at` string, date-time
        - `detail` string: Machine token only; free text is never forwarded.
      - `risk` Check, required
        - `state` 'passed' | 'failed' | 'unknown' | 'not_run' | 'error', required
        - `reason_code` string, required: Machine token; evidence_unavailable when the engine emitted nothing usable.
        - `observed_at` string, date-time
        - `detail` string: Machine token only; free text is never forwarded.
  - `limit` integer, required
  - `offset` integer, required: Compatibility echo; ignore when traversing with cursor.
  - `nextCursor` string, nullable, required: Pass a non-null value as the next cursor query parameter. null terminates this walk.
  - `partial` boolean, required: true until a successful finalized snapshot exists.
  - `finalized` boolean, required
  - `countsMayChange` boolean, required: When true, more rows or changed counters may appear while the job runs.
  - `requestId` string, required

## Other responses

- `400`: Error response.
- `401`: Error response.
- `404`: Error response.
- `429`: Rate limit exceeded.

---

[API](https://skmtc.dev/bounceless/apis/bounceless-api.md) - [All operations](https://skmtc.dev/bounceless/apis/bounceless-api/llms.txt) - [OpenAPI document](https://skmtc.dev/bounceless/apis/bounceless-api/revisions/d80696082abb?raw)
