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

# Get Validation Results (v2)

> Retrieve the result of an agentic email-validation job

Retrieve the status and result of a v2 validation job. Poll this endpoint until
`status` is `completed` or `failed`. The result is read-only and returns the
full agentic output, including any fields that were offloaded to storage for
large responses.

## Path Parameters

<ParamField path="job_id" type="string" required>
  The `job_id` returned by
  [Validate Email (v2)](/api-reference/validation-v2/validate-email).
</ParamField>

## Response

<ResponseField name="api_version" type="string">
  Always `v2`.
</ResponseField>

<ResponseField name="job_id" type="string">
  Unique identifier for the validation job.
</ResponseField>

<ResponseField name="status" type="string">
  Job status: `queued`, `processing`, `completed`, or `failed`.
</ResponseField>

<ResponseField name="submitted_at" type="string">
  ISO 8601 UTC timestamp when the job was created, e.g.
  `2026-06-25T12:00:00.123456+00:00`.
</ResponseField>

<ResponseField name="progress" type="object">
  Current pipeline step (while processing, when available).

  <Expandable title="progress properties">
    <ResponseField name="step" type="string">
      Current graph node, e.g. `analyze_email`, `evaluate_batch`, `verify`,
      `synthesize`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="model" type="string">
  The provider/model used, e.g. `anthropic/claude-sonnet-4-6` (present when
  completed).
</ResponseField>

<ResponseField name="extracted_text" type="string">
  The email text the validator evaluated (present when completed).
</ResponseField>

<ResponseField name="result" type="object">
  The validation result (present when `status` is `completed`).

  <Expandable title="result properties">
    <ResponseField name="overall_status" type="string">
      Overall assessment: `approved`, `needs_changes`, or `do not send`. Note:
      `do not send` contains spaces — this matches the API response exactly.
    </ResponseField>

    <ResponseField name="summary" type="object">
      Violation counts by severity.

      <Expandable title="summary properties">
        <ResponseField name="critical" type="integer">Count of critical violations</ResponseField>
        <ResponseField name="major" type="integer">Count of major violations</ResponseField>
        <ResponseField name="medium" type="integer">Count of medium violations</ResponseField>
        <ResponseField name="minor" type="integer">Count of minor violations</ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="email_profile" type="object">
      The agent's structured read of the email — intent, tone, claims, audience
      signals, disclosures present, data cited, products referenced.
    </ResponseField>

    <ResponseField name="violations" type="array">
      Signal-based findings from the agentic engine.

      <Expandable title="violation properties">
        <ResponseField name="signal_id" type="string">
          Signal identifier, e.g. `signal_mnpi_leak`.
        </ResponseField>

        <ResponseField name="signal_name" type="string">
          Human-readable signal name, e.g. `Material Non-Public Information (AI)`.
        </ResponseField>

        <ResponseField name="severity" type="string">
          `Critical`, `Major`, `Medium`, or `Minor`.
        </ResponseField>

        <ResponseField name="confidence" type="string">
          Confidence after adversarial verification: `high`, `medium`, or `low`.
        </ResponseField>

        <ResponseField name="quote" type="string">
          The offending text, verbatim.
        </ResponseField>

        <ResponseField name="char_from" type="integer">Start character offset of the quote.</ResponseField>
        <ResponseField name="char_to" type="integer">End character offset of the quote.</ResponseField>
        <ResponseField name="page" type="integer">Page number where the quote appears.</ResponseField>

        <ResponseField name="reasoning" type="string">
          The model's explanation of why the text violates the signal.
        </ResponseField>

        <ResponseField name="verifier_note" type="string">
          The adversarial verifier's note (confirms or downgrades the finding).
        </ResponseField>

        <ResponseField name="fix" type="object">
          Suggested remediation.

          <Expandable title="fix properties">
            <ResponseField name="action" type="string">`replace`, `insert_after`, `remove`, or `warning`.</ResponseField>
            <ResponseField name="suggested_text" type="string | null">The remediation text (null for `remove`/`warning`).</ResponseField>
            <ResponseField name="fix_note" type="string">Human-readable description of the fix.</ResponseField>
          </Expandable>
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="all_violations" type="array">
      Signal and regex findings merged into one list.
    </ResponseField>

    <ResponseField name="rule_violations" type="array">
      Deterministic `REGEX` / `REQUIRE_NEAR` rule findings only.
    </ResponseField>

    <ResponseField name="revalidation_recommended" type="boolean">
      True when more than one fix is found, suggesting a re-scan after applying fixes.
    </ResponseField>

    <ResponseField name="rewritten_text" type="string">
      Compliant rewrite (only when the rewrite loop is enabled and produced one).
    </ResponseField>

    <ResponseField name="rewrite_attempts" type="integer">
      Number of rewrite iterations (present with `rewritten_text`).
    </ResponseField>

    <ResponseField name="warnings" type="array">
      Array of strings — non-fatal warning messages for this run. Currently emitted when your account's
      custom rules could not be loaded and were therefore **not evaluated** — surfaced so a partial
      evaluation is never invisible. Omitted (or empty) when there are no warnings.
    </ResponseField>

    <ResponseField name="custom_rules_evaluated" type="boolean">
      Whether your account's custom rules were evaluated this run: `true` when they
      were applied (or there were none to apply), `false` when custom-rule loading
      failed (paired with a `warnings` entry). Absent for requests with no customer
      context (no custom-rule load attempted).
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="error" type="string | object">
  Error detail. The shape depends on the error class:

  * **Job failure** (HTTP `200`, `status` = `failed`): a **string** message, e.g.
    `"LLM provider unavailable"`.
  * **Request error** (HTTP `400` / `404` / `500`): an **object**
    `{ "code": string, "message": string }` — see the error table and the
    404 example below.
</ResponseField>

## Status Values

| Status       | Description                           |
| ------------ | ------------------------------------- |
| `queued`     | Job created and queued for processing |
| `processing` | Agentic validation in progress        |
| `completed`  | Validation completed successfully     |
| `failed`     | Validation failed with error          |

## Error Responses

| Status | Code             | Description                          |
| ------ | ---------------- | ------------------------------------ |
| 400    | `missing_job_id` | `job_id` is required                 |
| 404    | `not_found`      | No job exists for the given `job_id` |
| 500    | `internal_error` | Unexpected server error              |

<ResponseExample>
  ```json Processing theme={null}
  {
    "api_version": "v2",
    "job_id": "a1b2c3d4e5f6",
    "status": "processing",
    "submitted_at": "2026-06-25T12:00:00.123456+00:00",
    "progress": { "step": "verify" }
  }
  ```

  ```json Completed theme={null}
  {
    "api_version": "v2",
    "job_id": "a1b2c3d4e5f6",
    "status": "completed",
    "submitted_at": "2026-06-25T12:00:00.123456+00:00",
    "progress": { "step": "synthesize" },
    "model": "anthropic/claude-sonnet-4-6",
    "extracted_text": "Hey, the quarterly board meeting just wrapped...",
    "result": {
      "overall_status": "do not send",
      "summary": { "critical": 3, "major": 0, "medium": 0, "minor": 0 },
      "revalidation_recommended": true,
      "email_profile": {
        "communication_intent": "advisory",
        "tone": "urgent",
        "audience_signals": [
          "Recipient's family holds a position in the sender's company stock",
          "Sender has fiduciary or insider access to material non-public information"
        ],
        "claims": {
          "forward_looking": ["Full-year guidance will be revised downward by 10%"],
          "performance": ["Company missed quarterly revenue targets by $15 million"],
          "promissory": [],
          "comparative": []
        },
        "disclosures_present": [],
        "data_cited": ["$15 million revenue shortfall versus quarterly targets"]
      },
      "violations": [
        {
          "signal_id": "signal_mnpi_leak",
          "signal_name": "Material Non-Public Information (AI)",
          "severity": "Critical",
          "confidence": "high",
          "quote": "Sell before the official press release drops on Tuesday.",
          "char_from": 229,
          "char_to": 285,
          "page": 1,
          "reasoning": "This is an explicit trading instruction predicated entirely on MNPI...",
          "verifier_note": "Quote appears verbatim and constitutes an explicit, time-bound trading instruction predicated on MNPI.",
          "fix": {
            "action": "replace",
            "suggested_text": "Remove this sentence entirely. Trading recommendations must never be based on material non-public information.",
            "fix_note": "May contain material non-public information (MNPI). Violation of SEC Rule 10b-5 and FINRA Rule 2010."
          }
        }
      ]
    }
  }
  ```

  ```json Failed theme={null}
  {
    "api_version": "v2",
    "job_id": "a1b2c3d4e5f6",
    "status": "failed",
    "submitted_at": "2026-06-25T12:00:00.123456+00:00",
    "error": "LLM provider unavailable"
  }
  ```

  ```json 404 Not Found theme={null}
  {
    "api_version": "v2",
    "error": { "code": "not_found", "message": "Job a1b2c3d4e5f6 not found" }
  }
  ```
</ResponseExample>

## Example

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://{api-url}/api/v2/jobs/a1b2c3d4e5f6" \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```python Python theme={null}
  import requests
  import time

  API_KEY = "YOUR_API_KEY"
  API_BASE = "https://{api-url}"

  def get_results(job_id):
      while True:
          response = requests.get(
              f"{API_BASE}/api/v2/jobs/{job_id}",
              headers={"x-api-key": API_KEY}
          )
          result = response.json()

          if result["status"] in ("completed", "failed"):
              return result

          time.sleep(2)

  results = get_results("a1b2c3d4e5f6")
  print(results)
  ```

  ```javascript JavaScript theme={null}
  const axios = require('axios');

  const API_KEY = 'YOUR_API_KEY';
  const API_BASE = 'https://{api-url}';

  async function getResults(jobId) {
    while (true) {
      const response = await axios.get(
        `${API_BASE}/api/v2/jobs/${jobId}`,
        { headers: { 'x-api-key': API_KEY } }
      );

      if (['completed', 'failed'].includes(response.data.status)) {
        return response.data;
      }

      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  }

  const results = await getResults('a1b2c3d4e5f6');
  console.log(results);
  ```
</CodeGroup>
