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

> Retrieve the result of a v3 content-validation job

Retrieve the status and result of a v3 validation job started via
[Validate Content](/api-reference/validate/validate-content). Poll this
endpoint until `status` is `done` or `failed`.

## Path Parameters

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

## Response

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

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

<ResponseField name="status" type="string">
  Job status: `started`, `in_progress`, `done`, or `failed`.
</ResponseField>

<ResponseField name="model_engine" type="string">
  Engine that produced the result: `v2_frontier` or `anchor_3_0`.
</ResponseField>

<ResponseField name="fallback_engine" type="string">
  Present when an `anchor_3_0` request failed and fell back to `v2_frontier`
  automatically.
</ResponseField>

<ResponseField name="started" type="string">
  Time when the validation job started.
</ResponseField>

<ResponseField name="timestamp" type="string">
  Time when this result snapshot was generated.
</ResponseField>

<ResponseField name="error" type="string">
  Error details (present only when `status` is `failed`).
</ResponseField>

<ResponseField name="overall_status" type="string">
  Overall compliance 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="do_not_send" type="integer">
      Count of blocking severity violations
    </ResponseField>

    <ResponseField name="send_with_caution" type="integer">
      Count of caution severity violations
    </ResponseField>

    <ResponseField name="document_pages" type="integer">
      Number of pages in the document
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="violating_line_count" type="integer">
  Number of lines with at least one compliance violation. Absent for older
  jobs or when only grouped fixes exist (per-line positions unavailable).
</ResponseField>

<ResponseField name="compliant_line_count" type="integer">
  Number of lines with no violations. Absent for older jobs or when only
  grouped fixes exist.
</ResponseField>

<ResponseField name="total_line_count" type="integer">
  Total number of lines in the document. Absent for older jobs or when only
  grouped fixes exist.
</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="relevant_rule_ids" type="array">
  Rule IDs the model identified as relevant to the content. Present for the
  `anchor_3_0` engine (the SLM's per-request evaluated rule set); absent for
  `v2_frontier`.
</ResponseField>

<ResponseField name="input_tokens" type="integer">
  Input (prompt) tokens the `anchor_3_0` SLM consumed for this validation.
  Present for the `anchor_3_0` engine; absent for `v2_frontier` (which tracks
  usage separately).
</ResponseField>

<ResponseField name="output_tokens" type="integer">
  Output (generated) tokens the `anchor_3_0` SLM produced for this validation.
  Present for the `anchor_3_0` engine; absent for `v2_frontier`.
</ResponseField>

<ResponseField name="violations_by_line" type="array">
  One entry per violating line, with all rules violated and the best fix.
  Absent for older jobs or when only grouped fixes exist. Present but empty
  for fully compliant documents.

  <Expandable title="line violation properties">
    <ResponseField name="line_number" type="integer">
      1-indexed line number in the document
    </ResponseField>

    <ResponseField name="line_text" type="string">
      The text content of the violating line (trimmed)
    </ResponseField>

    <ResponseField name="char_from" type="integer">
      Character offset of the best fix's original text start
    </ResponseField>

    <ResponseField name="char_to" type="integer">
      Character offset of the best fix's original text end
    </ResponseField>

    <ResponseField name="page" type="integer">
      Page number where the violation appears
    </ResponseField>

    <ResponseField name="rule_count" type="integer">
      Number of distinct rules violated on this line
    </ResponseField>

    <ResponseField name="rules_violated" type="array">
      All rules violated on this line, sorted by severity then confidence.
      Each entry carries `rule_id` (canonical rule identifier — rule-pack `id`,
      or `cust_{customer_id}_{id}` for activated custom rules), `rule_name`,
      `rule_ref` (regulatory citation, e.g. `FINRA 2210(d)(1)(B)`), `severity`
      (`do_not_send` or `send_with_caution`), `confidence` (0–1), and `action`
      (`replace`, `insert_after`, `remove`, or `warning`).
    </ResponseField>

    <ResponseField name="best_fix" type="object">
      The recommended fix for this line (from the highest-severity,
      highest-confidence rule): `severity`, `rule_id`, `rule_name`, `rule_ref`,
      `action`, `suggested_text` (null when `action` is `remove`/`warning`),
      `human_action`, and `confidence`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="fixes" type="array">
  Individual fix entries (rule-centric, one per violation per quote). Each
  entry carries `rule_id` — the canonical rule identifier (rule-pack `id`, or
  `cust_{customer_id}_{id}` for activated custom rules).
</ResponseField>

<ResponseField name="fixes_group" type="object">
  Grouped fixes for rules that aggregate across pages. Each value additionally
  carries `rule_id` (the canonical rule identifier — also the key under which
  the group is stored in this object).
</ResponseField>

<ResponseField name="metadata" type="object">
  Document metadata used for scenario matching.
</ResponseField>

## Status Values

| Status        | Description                        |
| ------------- | ---------------------------------- |
| `started`     | Job created and started processing |
| `in_progress` | Validation in progress             |
| `done`        | Validation completed successfully  |
| `failed`      | Validation failed with error       |

## Error Responses

| Status | Description                                                   |
| ------ | ------------------------------------------------------------- |
| 403    | Forbidden — missing, invalid, inactive, or unresolved API key |
| 404    | Job Not Found                                                 |

<ResponseExample>
  ```json In Progress theme={null}
  {
    "api_version": "v3",
    "job_id": "a1b2c3",
    "status": "in_progress",
    "model_engine": "anchor_3_0",
    "started": "2026-06-25T12:00:00.123456+00:00",
    "timestamp": "2026-06-25T12:00:02.654321+00:00"
  }
  ```

  ```json Done theme={null}
  {
    "api_version": "v3",
    "job_id": "a1b2c3",
    "status": "done",
    "model_engine": "anchor_3_0",
    "overall_status": "do_not_send",
    "summary": {
      "do_not_send": 1,
      "send_with_caution": 0,
      "document_pages": 1
    },
    "violating_line_count": 2,
    "compliant_line_count": 3,
    "total_line_count": 5,
    "revalidation_recommended": true,
    "relevant_rule_ids": [
      "guarantee_of_returns",
      "missing_risk_disclosure"
    ],
    "input_tokens": 119,
    "output_tokens": 1920,
    "violations_by_line": [
      {
        "line_number": 2,
        "line_text": "Our fund guarantees 18% returns with no downside risk.",
        "char_from": 45,
        "char_to": 98,
        "page": 1,
        "rule_count": 1,
        "rules_violated": [
          {
            "rule_name": "Prohibited Promissory Language (Keywords)",
            "rule_ref": "FINRA 2210(d)(1)(B)",
            "severity": "do_not_send",
            "confidence": 0.92,
            "action": "replace"
          }
        ],
        "best_fix": {
          "severity": "do_not_send",
          "rule_name": "Prohibited Promissory Language (Keywords)",
          "rule_ref": "FINRA 2210(d)(1)(B)",
          "action": "replace",
          "suggested_text": "Our fund has historically delivered returns, though past performance does not guarantee future results.",
          "confidence": 0.92
        }
      }
    ],
    "fixes": [],
    "fixes_group": {},
    "metadata": {}
  }
  ```

  ```json Failed theme={null}
  {
    "api_version": "v3",
    "job_id": "a1b2c3",
    "status": "failed",
    "model_engine": "anchor_3_0",
    "error": "Validation engine unavailable"
  }
  ```
</ResponseExample>

## Example

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.zerodrift.ai/api/v3/jobs/a1b2c3" \
    -H "x-api-key: YOUR_API_KEY"
  ```

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

  API_KEY = "YOUR_API_KEY"
  API_BASE = "https://api.zerodrift.ai"

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

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

          time.sleep(2)

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

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

  const API_KEY = 'YOUR_API_KEY';
  const API_BASE = 'https://api.zerodrift.ai';

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

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

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

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