# Verify Emails in Bulk

> Check up to 10,000 email addresses in one request.

Requires an API key with the `write` scope.

The workspace needs a paid plan and a balance of at least the number of addresses you send, because the check is made up front. Only `good` and `bad` verdicts are charged, so `creditsUsed` can be lower than the count. The call waits for the provider, which works through the list in chunks of 100; large batches can take minutes, and anything the provider has not answered after 15 minutes comes back as `error` and is not charged. Set a long client timeout. This response is not wrapped in `data`.

## Body Parameters

<ParamField body="emails" type="array" required>
  1 to 10,000 email addresses. One invalid address rejects the whole request.
</ParamField>

## Response

<ResponseField name="results" type="array">
  One verdict per address, in the order you sent them.

  <Expandable title="results">
    <ResponseField name="email" type="string">The address that was checked.</ResponseField>
    <ResponseField name="quality" type="string">`good`, `bad`, `unknown` or `error`. Only `good` and `bad` use a credit.</ResponseField>
    <ResponseField name="result" type="string">The reason: `accepted`, `probable`, `rejected`, `not_found` or `error`.</ResponseField>
    <ResponseField name="didYouMean" type="string">A suggested correction for a typo, or `null`.</ResponseField>
    <ResponseField name="free" type="boolean">`true` for a free-provider address such as Gmail.</ResponseField>
    <ResponseField name="role" type="boolean">`true` for a role address such as info@ or support@.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="creditsUsed" type="integer">Credits charged for this request.</ResponseField>

<RequestExample>
```bash cURL
curl -X POST "https://api.foxreach.io/api/v1/verification/verify/bulk" \
  -H "X-API-Key: otr_your_key" \
  -H "Content-Type: application/json" \
  -d '{"emails": ["john@acme.com", "jane@acme.com"]}'
```

```python Python SDK (beta)
from foxreach import FoxReach

client = FoxReach(api_key="otr_your_key")
result = client.verification.verify_bulk(["john@acme.com", "jane@acme.com"])
```

```typescript TypeScript SDK (beta)
import { FoxReach } from "foxreach";

const client = new FoxReach({ apiKey: "otr_your_key" });
const result = await client.verification.bulkVerify(["john@acme.com", "jane@acme.com"]);
```
</RequestExample>

<ResponseExample>
```json
{
  "results": [
    { "email": "john@acme.com", "quality": "good", "result": "accepted", "didYouMean": null, "free": false, "role": false },
    { "email": "jane@acme.com", "quality": "bad", "result": "rejected", "didYouMean": null, "free": false, "role": false }
  ],
  "creditsUsed": 2
}
```
</ResponseExample>

## Errors

| Status | Description |
|--------|-------------|
| `401` | Missing, invalid, revoked or expired API key |
| `403` | API key does not have the required scope: `write` |
| `402` | `insufficient_verification_credits`: `{"detail": {"code": "insufficient_verification_credits", "message": "...", "balance": 0, "required": 1}}` |
| `403` | `upgrade_required` on the Free plan: `{"detail": {"code": "upgrade_required", "limit_type": "email_verification", "message": "..."}}`. A missing scope also returns 403 with a plain `detail` string |
| `422` | `emails` is empty, has more than 10,000 entries, or contains an invalid address |

## Rate Limit

- **100 requests per minute, per API key.** Fixed 60-second window.
- Every response includes `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` (unix epoch seconds).
- A `429` response includes a `Retry-After` header (seconds until the bucket resets).

For client-side patterns (`Retry-After`, exponential backoff, monitoring `X-RateLimit-Remaining`), see [Rate Limiting](/rate-limiting).
