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

# Validate Email (v2)

> Submit an email to the agentic validator — async or sync

Submit email content to the agentic email validator. By default the request is
processed **asynchronously**: the endpoint returns a `job_id` you poll via
[Get Validation Results (v2)](/api-reference/validation-v2/get-results). Set
`mode: "sync"` to run the validation inline and receive the completed result in
a single response.

## Request Body

<ParamField body="email_text" type="string">
  The email content to validate. This is the canonical field; `text_snippet`
  (string) and `email_bytes` (base64-encoded UTF-8) are accepted as aliases.
  **One of** `email_text`, `text_snippet`, or `email_bytes` is required.
</ParamField>

<ParamField body="mode" type="string" default="async">
  Execution mode: `async` (default) returns `202` with a `job_id` to poll;
  `sync` runs the agentic graph inline and returns the completed result with
  `200`. Sync requests above the size cap (default 20,000 characters) or that
  fail inline automatically fall back to async.
</ParamField>

<ParamField body="metadata" type="object">
  Optional metadata merged into the job. `document_type` is always forced to
  `email` so the request routes to the agentic engine.

  <Expandable title="common metadata fields">
    <ParamField body="audience_hint" type="string">
      Intended audience, e.g. `retail_US`, `professional_US`.
    </ParamField>

    <ParamField body="jurisdiction" type="string">
      Regulatory jurisdiction, e.g. `US`.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="document_category" type="string">
  Explicit scenario id to validate against, e.g. `scenario_email_general`. When
  omitted, the validator matches scenarios by metadata: every email matches an
  audience-agnostic baseline carrying core signals — material non-public information
  (MNPI), market manipulation, high-pressure sales, and client-data privacy — and
  `audience_hint: retail_US` additionally applies retail-disclosure signals. Your
  account's active custom rules (from policy imports) are evaluated as well. If no
  scenario/signals match at all, the job **fails** rather than returning a false
  `approved`.
</ParamField>

<ParamField body="llm_provider" type="string">
  Provider hint (`openai`, `anthropic`, `gemini`). Honored only if the customer
  is configured to allow provider override; otherwise the customer's assigned
  provider is used.
</ParamField>

<ParamField body="llm_model" type="string">
  Model hint, e.g. `claude-sonnet-4-6`. Subject to the same override rule as
  `llm_provider`.
</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">
  `queued` for async submissions. For `sync` responses the full status
  vocabulary applies (`completed` / `failed`).
</ResponseField>

<ResponseField name="mode" type="string">
  Mode the request was actually processed in: `async` or `sync`. A `sync`
  request that fell back returns `async`.
</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="poll" type="object">
  Where to poll for the result (async only).

  <Expandable title="poll properties">
    <ResponseField name="method" type="string">
      Always `GET`.
    </ResponseField>

    <ResponseField name="url" type="string">
      Poll URL, e.g. `/api/v2/jobs/{job_id}`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="usage" type="object">
  Billing usage counters (when usage tracking succeeds).

  <Expandable title="usage properties">
    <ResponseField name="monthly_count" type="integer">
      Validations this month.
    </ResponseField>

    <ResponseField name="annual_count" type="integer">
      Validations this year.
    </ResponseField>
  </Expandable>
</ResponseField>

<Note>
  For the `sync` response body (HTTP 200), the envelope is identical to a
  **completed** poll — see
  [Get Validation Results (v2)](/api-reference/validation-v2/get-results) — with
  `"mode": "sync"` added.
</Note>

## Error Responses

| Status | Code                  | Description                                                                       |
| ------ | --------------------- | --------------------------------------------------------------------------------- |
| 400    | `missing_email`       | No email content provided (one of `email_text`, `text_snippet`, or `email_bytes`) |
| 400    | `invalid_email_bytes` | `email_bytes` is not valid base64 UTF-8                                           |
| 400    | `invalid_mode`        | `mode` must be `async` or `sync`                                                  |
| 500    | `internal_error`      | Unexpected server error                                                           |

<ResponseExample>
  ```json 202 Accepted (async) theme={null}
  {
    "api_version": "v2",
    "job_id": "a1b2c3d4e5f6",
    "status": "queued",
    "mode": "async",
    "submitted_at": "2026-06-25T12:00:00.123456+00:00",
    "poll": { "method": "GET", "url": "/api/v2/jobs/a1b2c3d4e5f6" },
    "usage": { "monthly_count": 42, "annual_count": 1234 }
  }
  ```

  ```json 400 Bad Request theme={null}
  {
    "api_version": "v2",
    "error": { "code": "missing_email", "message": "email_text is required" }
  }
  ```
</ResponseExample>

## Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://{api-url}/api/v2/emails/validate" \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "email_text": "Hey, the quarterly board meeting just wrapped. We missed our revenue targets by $15 million. Sell before the official press release drops on Tuesday.",
      "mode": "async",
      "metadata": { "audience_hint": "retail_US", "jurisdiction": "US" }
    }'
  ```

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

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

  response = requests.post(
      f"{API_BASE}/api/v2/emails/validate",
      headers={
          "x-api-key": API_KEY,
          "Content-Type": "application/json"
      },
      json={
          "email_text": "Hey, the quarterly board meeting just wrapped. We missed our revenue targets by $15 million. Sell before the official press release drops on Tuesday.",
          "mode": "async",
          "metadata": {"audience_hint": "retail_US", "jurisdiction": "US"}
      }
  )

  print(response.json())  # -> {"job_id": "...", "status": "queued", ...}
  ```

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

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

  const response = await axios.post(
    `${API_BASE}/api/v2/emails/validate`,
    {
      email_text: 'Hey, the quarterly board meeting just wrapped. We missed our revenue targets by $15 million. Sell before the official press release drops on Tuesday.',
      mode: 'async',
      metadata: { audience_hint: 'retail_US', jurisdiction: 'US' }
    },
    {
      headers: {
        'x-api-key': API_KEY,
        'Content-Type': 'application/json'
      }
    }
  );

  console.log(response.data);
  ```
</CodeGroup>
