# Errors

> How the Emailit API reports errors. Response body formats, HTTP status codes and what they mean, and fixes for the error messages you'll see most.

The Emailit API uses HTTP status codes to tell you whether a request worked. Codes in the `2xx` range mean success, `4xx` codes mean something about the request needs to change, and `5xx` codes mean something went wrong on our side. This page describes the error bodies, every status code the API returns and how to fix the most common errors.

## Error response formats

Every error body is a JSON object with an `error` field. The exact shape depends on where the request failed. Write your error handling to read `error`, then `message` when it's present, then any extra fields the endpoint documents.

### Request errors

Authentication failures, permission errors, malformed JSON and other errors raised before an endpoint runs use the standard HTTP error format:

```json
{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "API key required"
}
```

| Field | Description |
| --- | --- |
| `statusCode` | The HTTP status code. |
| `error` | The HTTP reason phrase, such as `Unauthorized` or `Forbidden`. |
| `message` | What went wrong, in plain language. |

### Validation errors

When a query parameter or body field has the wrong type, is missing, or is out of range, the API rejects the request with `400` before it runs and lists each problem in `details`:

```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Validation error",
  "details": [
    {
      "instancePath": "/limit",
      "schemaPath": "#/properties/limit/maximum",
      "keyword": "maximum",
      "params": { "comparison": "<=", "limit": 100 },
      "message": "must be <= 100"
    }
  ]
}
```

`instancePath` points to the field (`/limit`, `/to`, `/attachments/0/filename`), and `message` describes the rule it broke. On a few endpoints, such as [Send an email](/docs/api-reference/emails/send/), these errors return only `{"error": "Bad Request"}`.

### Resource errors

Errors raised by an endpoint, such as a missing object or a duplicate name, return `error` and often `message`:

```json
{
  "error": "Email not found",
  "message": "Email with ID 'em_4KYof1ZzXndZE2VPi0DgULiekG8' not found in your workspace"
}
```

Some errors add fields that help you recover:

| Field | Returned with | Contains |
| --- | --- | --- |
| `existing` | `409` when you create a duplicate domain, API key, audience, contact or subscriber | The object that already exists, so you can use it instead. |
| `usage` | `422` when a plan limit is reached | `used`, `limit` and, for audiences, `plan`. |
| `required_plan` | `403` with `error: "plan_required"` | The lowest plan that includes the feature, such as `pro`. |
| `code` | Some `403` and `422` errors | A stable machine-readable code, such as `unverified_workspace_recipient` or `events_offset_too_large`. |
| `missing` | `404` from [Bulk update contacts](/docs/api-reference/contacts/bulk/) | The contact IDs that weren't found. |

### Send validation errors

[Send an email](/docs/api-reference/emails/send/) and [Forward an email](/docs/api-reference/emails/forward/) check the whole message at once and return every problem in `validation_errors`:

```json
{
  "error": "Validation failed",
  "validation_errors": [
    "Missing required field: subject",
    "Invalid to email address at index 1: ada@example"
  ]
}
```

### Field errors

Templates, campaigns and automations return validation problems grouped by field:

```json
{
  "message": "Validation failed",
  "errors": {
    "alias": ["Alias must contain only lowercase letters (a-z), numbers (0-9), underscores (_), and hyphens (-)"]
  }
}
```

### Rate limit errors

`429` responses from the sending endpoints include the limit you hit and how long to wait. See [Rate limits](/docs/api-reference/rate-limits/).

```json
{
  "error": "Rate limit exceeded",
  "message": "Too many requests. Maximum 2 messages per second allowed.",
  "limit": 2,
  "current": 2,
  "retry_after": 1
}
```

## HTTP status codes

| Code | Meaning | Typical causes in the Emailit API |
| --- | --- | --- |
| `200` | OK | The request worked. Sends, updates, deletes and reads return `200`. |
| `201` | Created | A domain, API key, audience, subscriber, contact, template, webhook or other object was created. |
| `202` | Accepted | A DMARC report upload was accepted for processing. |
| `204` | No Content | A form was deleted. The response has no body. |
| `400` | Bad Request | Invalid JSON, a missing required field, a value of the wrong type or out of range, an invalid `Idempotency-Key`, or no fields to update. |
| `401` | Unauthorized | The API key is missing, invalid, deleted or regenerated, or an OAuth token expired. See [Authentication](/docs/api-reference/authentication/#authentication-errors). |
| `402` | Payment Required | The workspace doesn't have enough credits for the send, retry or verification. |
| `403` | Forbidden | The key's scope doesn't allow the endpoint, a domain-restricted key sent from another domain, the workspace is suspended or not yet verified, the sending domain is paused, or the feature needs a higher plan. |
| `404` | Not Found | The object doesn't exist in this workspace, or a template alias has no published version. |
| `409` | Conflict | An object with the same name or email already exists, or a request with the same `Idempotency-Key` is still running. |
| `413` | Payload Too Large | The composed email is larger than 40 MB, or a DMARC report upload is larger than 10 MB. |
| `422` | Unprocessable Entity | The request is valid but can't be done right now: the `from` domain isn't verified, an attachment couldn't be fetched, the email's status doesn't allow cancel or retry, its content was already purged, or a plan limit was reached. |
| `429` | Too Many Requests | The workspace hit its per-second or daily sending limit, or the hourly forward limit. |
| `500` | Internal Server Error | Something failed on our side. Retry with backoff, and contact support if it persists. |
| `503` | Service Unavailable | A temporary outage of a dependency, such as the idempotency store or the authentication database. Retry with backoff. |

## Common errors and how to fix them

| Status | `error` | Cause | Fix |
| --- | --- | --- | --- |
| `400` | `Validation failed` | A send is missing `from`, `to`, `subject` or content, or has an invalid address or attachment. | Fix each item listed in `validation_errors`. |
| `400` | `Invalid JSON in request body` (in `message`) | The body isn't valid JSON. | Check quoting and trailing commas, and send `Content-Type: application/json`. |
| `400` | `Invalid Idempotency-Key` | The key is longer than 256 characters or has characters other than letters, digits, `-` and `_`. | Use a UUID or a similar safe value. |
| `402` | `Insufficient credits` | Credits ran out. Each recipient costs one credit. | Buy credits or turn on [auto-refill](/docs/billing/auto-refill/). |
| `403` | `Workspace not verified` | The workspace is in sandbox mode and a recipient isn't a workspace member. | Request [production access](/docs/workspaces/production-access/). |
| `403` | `Domain paused` | Sending from this domain is paused because of its [sending health](/docs/deliverability/sending-health/). | Fix the bounce or complaint problem, then contact support. |
| `403` | `Domain not authorized` | The API key is restricted to another sending domain. | Send from the key's domain or use another key. |
| `403` | `plan_required` | The feature, such as DMARC reports or webhook filters, isn't on your plan. | Upgrade to the plan in `required_plan`. |
| `403` | `mjml_alpha` | The request creates or changes MJML, or calls an MJML endpoint. MJML is in alpha and open to the Emailit team only. | Use another editor or content type. See [MJML editors and API](/docs/templates/mjml/#who-can-use-mjml). |
| `404` | `Template not found` | The template ID doesn't exist, or the alias has no published version. | [Publish](/docs/api-reference/templates/publish/) a version of the template. |
| `409` | `… already exists` | You created an object with a name or email that's already taken. | Use the object in `existing`, or pick another name. |
| `409` | `Idempotency key in progress` | Another request with the same key hasn't finished. | Wait a moment and retry with the same key. |
| `413` | `Message too large` | The email, including attachments, is over 40 MB. | Send large files as links instead of attachments. |
| `422` | `Domain not verified` | The `from` address isn't on a verified sending domain of this workspace. | [Verify the domain](/docs/domains/verification/) or change `from`. |
| `422` | `Attachment error` | An attachment `url` couldn't be fetched within 30 seconds, isn't reachable, or is larger than 25 MB. | Check the URL is public and the file is small enough, or send `content` instead. |
| `422` | `Cannot cancel email`, `Cannot retry email`, `Cannot update email` | The email's status doesn't allow the action, it's within 3 minutes of its scheduled time, or its content was purged. | Check the email's `status`. See each endpoint for the rules. |
| `422` | `Page is too deep` | You paged past offset 2,500 of [List events](/docs/api-reference/events/list/). | Narrow the results with `type` or `created_at` filters. |
| `429` | `Rate limit exceeded`, `Daily limit exceeded` | The workspace hit its sending limit. | Wait `retry_after` seconds. See [Rate limits](/docs/api-reference/rate-limits/). |

## Retry safely

- Retry `429`, `500` and `503` responses after a delay. Use the `retry-after` header when it's present, and exponential backoff otherwise. [Rate limits](/docs/api-reference/rate-limits/#retry-with-backoff) has example code.
- Don't retry other `4xx` errors unchanged. They fail the same way until you fix the request.
- When you retry a send after a timeout or a `5xx` error, reuse the same [`Idempotency-Key`](/docs/api-reference/idempotency/) so the email isn't sent twice.

## Related

  - [Authentication](/docs/api-reference/authentication/): Credentials, scopes and every authentication error.
  - [Rate limits](/docs/api-reference/rate-limits/): Sending limits, headers and backoff.
  - [Idempotency](/docs/api-reference/idempotency/): Retry sends without sending twice.
  - [Request logs](/docs/logs/request-logs/): See the request and response of every failed API call.

---
Source: https://emailit.com/docs/api-reference/errors/
