# Errors

Handle IronDome API errors for invalid requests, authentication, quotas and service failures. See response formats and when to retry.

Handle API errors separately from email classifications. A disposable address is a successful check; a timeout or unavailable service is not evidence that an address is acceptable.

## Error format

```json
{
  "error": {
    "code": "invalid_email",
    "message": "Provide a syntactically valid email address."
  }
}
```

Branch on HTTP status and `error.code`. Messages are explanatory and may change. Keep the `X-Request-ID` response header for troubleshooting; redact credentials and email bodies.

## Status codes

| Status | Codes | Recovery |
| --- | --- | --- |
| `400` | `empty_body`, `invalid_content_length`, `invalid_body_length`, `invalid_json` | Correct the body schema or framing. |
| `400` | `empty_batch` | Provide at least one email. |
| `401` | `authorization_required`, `invalid_authorization`, `invalid_api_key`, `expired_api_key`, `inactive_api_key`, `revoked_api_key` | Check the full credential and its account status; replace it if necessary. |
| `403` | `insufficient_scope` | Use a credential permitted to perform the operation. |
| `403` | `free_usage_only` | Read paid usage in the dashboard instead of `/v1/usage`. |
| `404` | `not_found` | Check the route under `https://api.irondome.dev`. |
| `405` | `method_not_allowed` | Use the method in `Allow`. |
| `411` | `content_length_required` | Send a known-length JSON body. |
| `413` | `body_too_large`, `batch_too_large` | Reduce the body or split into batches of at most 100. |
| `422` | `invalid_email` | Ask the user to correct the address. |
| `429` | `monthly_quota_exceeded` | Wait for the UTC monthly reset or explicitly arrange paid access. |
| `500` | `internal_error` | Keep the request ID and investigate repeated failures. |
| `503` | `service_unavailable` | Preserve the unavailable state; respect `Retry-After` before another attempt. |

Single-check bodies are limited to 1,024 UTF-8 bytes; bulk bodies to 65,536 bytes. See [requests](/docs/api/check#request) and [bulk errors](/docs/api/bulk#request-level-errors).

## Bulk item errors

An accepted batch returns HTTP `200` even when individual emails are invalid. Inspect each item's `error` and use its zero-based `index` to match it to the submitted list.

## Timeouts and retries

Authentication failures include `WWW-Authenticate: Bearer`. Service-unavailable responses include `Retry-After: 5`, in seconds. Free-quota exhaustion persists until monthly reset or an explicit authorization change; short retry loops do not help.

A lost response, canceled request, or timeout after submission is ambiguous: the check may have completed and consumed usage. The check endpoints provide no idempotency-key contract. Another attempt can count again.

Do not automatically retry malformed requests, invalid addresses, authentication failures, or exhausted quota. For transient failures, use bounded retries with backoff and jitter only if your application accepts possible repeated usage. Preserve a total deadline for signup.

Consult [service status](https://status.irondome.dev) for persistent failures. Choose an explicit unavailable-check policy instead of returning an invented non-disposable result.

## Supabase hook errors

The [Supabase integration](/docs/guides/supabase#signup-outcomes) uses a hook envelope. Transport HTTP `200` with an `error.http_code` can deny signup. Do not apply REST success handling to hook responses.
