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

# POST /validate

> Validate an email address with device fingerprinting and fraud detection

## Overview

The `/validate` endpoint is the core of Vouch's API. It performs comprehensive email validation including syntax checking, disposable email detection, MX verification, and device fingerprinting.

<Note>
  You can use either the versioned endpoint `/v1/validate` or the latest endpoint `/validate`
</Note>

## Authentication

<ParamField header="Authorization" type="string" required>
  Bearer token with your API key

  ```
  Authorization: Bearer your_api_key_here
  ```
</ParamField>

<ParamField header="X-Project-Id" type="string" required>
  Your project ID

  ```
  X-Project-Id: your_project_id
  ```
</ParamField>

## Request Body

<ParamField body="email" type="string" required>
  The email address to validate (will be normalized to lowercase)

  ```json theme={null}
  "user@example.com"
  ```
</ParamField>

<ParamField body="fingerprintHash" type="string">
  Device fingerprint hash for client-side validation and device tracking.

  ```json theme={null}
  "abc123def456789..."
  ```
</ParamField>

<ParamField body="sdkVersion" type="string">
  SDK version identifier (automatically included by SDKs)

  ```json theme={null}
  "@vouch-in/js@1.0.0"
  ```
</ParamField>

<ParamField body="ip" type="string">
  **Server-side only:** Override client IP address for validation. If not provided, the API will use the request's IP address from headers (CF-Connecting-IP or X-Forwarded-For).

  Only available when using a **server API key**.

  ```json theme={null}
  "192.168.1.1"
  ```
</ParamField>

<ParamField body="userAgent" type="string">
  **Server-side only:** Override User-Agent for validation. If not provided, the API will use the request's User-Agent header.

  Only available when using a **server API key**.

  ```json theme={null}
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
  ```
</ParamField>

<ParamField body="validations" type="object">
  Optional override for which validations to run and their actions (allow/flag/block)

  ```json theme={null}
  {
    "syntax": "block",
    "disposable": "block",
    "mx": "block",
    "roleEmail": "flag",
    "alias": "flag",
    "device": "flag",
    "ip": "flag"
  }
  ```
</ParamField>

<Note>
  The SDKs automatically construct the request body. When using the API directly, ensure all required fields are included.
</Note>

## Response

<ResponseField name="checks" type="object" required>
  Individual validation check results. Each check contains:

  <Expandable title="CheckResult Structure">
    <ResponseField name="pass" type="boolean">
      Whether the check passed
    </ResponseField>

    <ResponseField name="error" type="string">
      Error message if check failed
    </ResponseField>

    <ResponseField name="latency" type="number">
      Check execution time in milliseconds
    </ResponseField>

    <ResponseField name="metadata" type="object">
      Additional check-specific data
    </ResponseField>
  </Expandable>

  Available checks include: `syntax`, `disposable`, `mx`, `roleEmail`, `alias`, `device`, `ip`
</ResponseField>

<ResponseField name="metadata" type="object" required>
  Validation metadata

  <Expandable title="Metadata">
    <ResponseField name="fingerprintHash" type="string | null">
      Device fingerprint hash (null if no fingerprint provided)
    </ResponseField>

    <ResponseField name="previousSignups" type="number">
      Number of previous signups from this device
    </ResponseField>

    <ResponseField name="totalLatency" type="number">
      Total validation time in milliseconds
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="message" type="string | null" required>
  Human-friendly error message when the recommendation is `flag` or `block` (e.g. "Please use a permanent email address, not a temporary one."). `null` when the recommendation is `allow`.
</ResponseField>

<ResponseField name="recommendation" type="string" required>
  Overall recommendation based on all checks: `allow`, `flag`, or `block`
</ResponseField>

<ResponseField name="signals" type="array" required>
  Array of signal identifiers detected during validation (e.g., `["disposable_email", "vpn_detected"]`)
</ResponseField>

## Example Request

<CodeGroup>
  ```bash cURL (Server-side) theme={null}
  curl --request POST \
    --url https://api.vouch.expert/validate \
    --header 'Authorization: Bearer your_server_api_key' \
    --header 'Content-Type: application/json' \
    --header 'X-Project-Id: your_project_id' \
    --data '{
      "email": "user@example.com",
      "ip": "192.168.1.1",
      "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
    }'
  ```

  ```javascript JavaScript (Server-side) theme={null}
  const response = await fetch('https://api.vouch.expert/validate', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer your_server_api_key',
      'X-Project-Id': 'your_project_id',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      email: 'user@example.com',
      ip: '192.168.1.1',
      userAgent: 'Mozilla/5.0...'
    })
  });

  const result = await response.json();
  ```

  ```python Python (Server-side) theme={null}
  import requests

  response = requests.post(
      'https://api.vouch.expert/validate',
      headers={
          'Authorization': 'Bearer your_server_api_key',
          'X-Project-Id': 'your_project_id',
          'Content-Type': 'application/json'
      },
      json={
          'email': 'user@example.com',
          'ip': '192.168.1.1',
          'userAgent': 'Mozilla/5.0...'
      }
  )

  result = response.json()
  ```

  ```go Go (Server-side) theme={null}
  package main

  import (
      "bytes"
      "encoding/json"
      "net/http"
  )

  func main() {
      payload := map[string]interface{}{
          "email": "user@example.com",
          "ip": "192.168.1.1",
          "userAgent": "Mozilla/5.0...",
      }

      jsonData, _ := json.Marshal(payload)

      req, _ := http.NewRequest("POST", "https://api.vouch.expert/validate", bytes.NewBuffer(jsonData))
      req.Header.Set("Authorization", "Bearer your_server_api_key")
      req.Header.Set("X-Project-Id", "your_project_id")
      req.Header.Set("Content-Type", "application/json")

      client := &http.Client{}
      resp, _ := client.Do(req)
      defer resp.Body.Close()
  }
  ```
</CodeGroup>

<Note>
  **Client-side requests**: Use the JavaScript/React SDKs which automatically include device fingerprinting in the `fingerprint` field.

  **Server-side requests**: Only provide `ip` and `userAgent` if you need to override the request's headers.
</Note>

## Example Response

```json theme={null}
{
  "checks": {
    "syntax": {
      "pass": true,
      "latency": 0.8
    },
    "disposable": {
      "pass": true,
      "latency": 12.3
    },
    "mx": {
      "pass": true,
      "latency": 45.2
    },
    "roleEmail": {
      "pass": true,
      "latency": 0.5
    },
    "alias": {
      "pass": true,
      "latency": 0.3
    },
    "device": {
      "pass": true,
      "latency": 15.7
    },
    "ip": {
      "pass": true,
      "latency": 8.4
    }
  },
  "message": null,
  "metadata": {
    "fingerprintHash": "abc123def456789",
    "previousSignups": 0,
    "totalLatency": 83.2
  },
  "recommendation": "allow",
  "signals": []
}
```

### Example with Signals

```json theme={null}
{
  "checks": {
    "syntax": {
      "pass": true,
      "latency": 0.8
    },
    "disposable": {
      "pass": false,
      "latency": 12.3
    },
    "mx": {
      "pass": true,
      "latency": 45.2
    },
    "device": {
      "pass": false,
      "latency": 15.7
    },
    "ip": {
      "pass": false,
      "latency": 8.4
    }
  },
  "message": "Please use a permanent email address, not a temporary one.",
  "metadata": {
    "fingerprintHash": "abc123def456789",
    "previousSignups": 3,
    "totalLatency": 82.4
  },
  "recommendation": "block",
  "signals": [
    "disposable_email",
    "device_reuse",
    "device_seen_3_times",
    "vpn_detected"
  ]
}
```

## Error Responses

All errors return an error object with HTTP status codes.

<ResponseExample>
  ```json 400 - Invalid Request theme={null}
  {
    "error": "Invalid email format"
  }
  ```

  ```json 401 - Unauthorized theme={null}
  {
    "error": "Invalid API key"
  }
  ```

  ```json 402 - Quota Exceeded theme={null}
  {
    "error": "Monthly validation quota exceeded"
  }
  ```

  ```json 429 - Rate Limited theme={null}
  {
    "error": "Too many requests"
  }
  ```

  ```json 500 - Server Error theme={null}
  {
    "error": "An internal error occurred"
  }
  ```
</ResponseExample>

## Rate Limits

| Key Type   | Rate Limit     | Window   |
| ---------- | -------------- | -------- |
| Client Key | 1,000 requests | Per hour |
| Server Key | 5,000 requests | Per hour |

<Warning>
  Rate limits are per project. If you exceed the limit, you'll receive a 429 error with a `retryAfter` value in seconds.
</Warning>

## Quota Management

Each plan includes a monthly validation quota. Track your usage in the dashboard or via the response headers:

```
X-Quota-Limit: 10000
X-Quota-Used: 2345
X-Quota-Remaining: 7655
X-Quota-Reset: 2024-01-01T00:00:00Z
```

## Best Practices

<AccordionGroup>
  <Accordion title="Use the Right API Key" icon="key">
    * **Client keys** for browser/mobile apps (includes automatic fingerprinting)
    * **Server keys** for backend validation (can override IP/User-Agent)
    * Never expose server keys in client-side code
  </Accordion>

  <Accordion title="Handle Recommendations Appropriately" icon="shield">
    * **block**: Reject the signup immediately
    * **flag**: Allow signup but mark for review, or require additional verification
    * **allow**: Proceed normally
  </Accordion>

  <Accordion title="Cache Results When Appropriate" icon="database">
    * Cache validation results for repeated validations of the same email
    * Set TTL based on your use case (e.g., 24 hours)
    * Invalidate cache if user changes email
  </Accordion>

  <Accordion title="Provide Good User Experience" icon="user">
    * **Option 1:** Use the `message` field to display user-friendly error messages directly
    * **Option 2:** Check individual `checks` for custom error messages and business logic
    * Don't expose internal validation details (signals, metadata) to users
    * Consider allowing flagged emails with additional verification
  </Accordion>

  <Accordion title="Monitor Your Quota" icon="chart-line">
    * Set up alerts when approaching quota limits
    * Upgrade plan before hitting limits
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Validation Types" icon="shield" href="/validation/overview">
    Learn about each validation check
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/guides/error-handling">
    Handle errors gracefully
  </Card>

  <Card title="Use SDKs" icon="box" href="/sdks/javascript">
    Use our SDKs for easier integration
  </Card>

  <Card title="Best Practices" icon="star" href="/guides/best-practices">
    Production optimization tips
  </Card>
</CardGroup>
