# Why am I getting an invalid_access error?

> A 422 invalid_access means your API key lacks permission for the action. Here is how to tell that apart from a missing User-Agent header (a 403), an unverified or mismatched domain (also a 422), and new-account sending restrictions.

A `422 invalid_access` means your request authenticated fine — the API key is valid — but the key **does not have permission** for the action you tried. This is the single most common cause: using a **sending-only key** (`sending_access`) to manage resources.

```json
{
  "statusCode": 422,
  "name": "invalid_access",
  "message": "This API key does not have permission for this action."
}
```

> **Note:** A `422 invalid_access` is about **permissions**, not authentication. A bad or revoked key returns `403 invalid_api_key`, and a missing key returns `401 missing_api_key`. If you are seeing a 401 or 403 auth error, see [Authentication](https://www.mailblastr.com/docs/authentication).

## Cause 1 — a sending-only key managing resources

API keys come in two permission levels:

| Permission | Can do |
| --- | --- |
| **full_access** | Send email **and** manage resources — domains, audiences, contacts, campaigns, and API keys. |
| **sending_access** | Send email **only**. Cannot create, update, or delete domains, audiences, contacts, campaigns, or other API keys. |

If you call an endpoint like `POST /domains`, `DELETE /audiences/:id`, or `POST /api-keys` with a `sending_access` key, you get `422 invalid_access`. The fix is to use a `full_access` key for management calls and reserve the `sending_access` key for `POST /emails`.

> **Warning:** Keeping a narrow `sending_access` key on your sending servers is the **right** security posture — do not "fix" a permission error by upgrading that key. Instead, run management tasks with a separate `full_access` key from a trusted environment.

## Cause 2 — an unverified from-domain (also a 422)

A frequent point of confusion: sending from a domain you have not verified returns a `422 validation_error`, because the request body itself is rejected before any permission check on the resource.

```json
{
  "statusCode": 422,
  "name": "validation_error",
  "message": "The domain is not verified. Verify it before sending."
}
```

You can only send from a domain (or a subdomain of a domain) you have added and verified by publishing its SPF/DKIM/DMARC DNS records. If the `from` address is not even a valid email, you instead get `422 invalid_from_address`. See the full [Errors](https://www.mailblastr.com/docs/api/errors) reference for every name and status code.

> **Warning:** A subtle variant: you verified a **subdomain** (e.g. `sending.yourdomain.com`) but your `from` uses the **root** (`you@yourdomain.com`), or vice-versa. The `from` domain must match a verified domain **exactly**, including the subdomain. Either change the `from` to your verified domain, or add and verify the exact domain you want to send from.

## Cause 3 — new-account sending restrictions

A brand-new account starts in a restricted **review mode** until production access is granted. While in review mode:

- You can only send to **verified recipient addresses** — sending to an arbitrary recipient is rejected.
- Daily send volume and send rate are capped to small starter limits.
- Your verified from-domain still works, but the recipient must also be verified.

> **Note:** Review-mode rejections surface as send failures rather than a clean permission error. If sends to verified recipients succeed but sends to new addresses fail, your account is almost certainly still in review mode — request production access. See [Usage limits](https://www.mailblastr.com/docs/api/limits).

## Cause 4 — a missing User-Agent header

This one bites people who **hand-roll** HTTP requests (the official [`mailblastr`](https://www.mailblastr.com/docs/resources/sdks) SDK sets a `User-Agent` for you, so SDK users never hit this). Every call to the API surface (`/emails`, `/domains`, `/audiences`, `/campaigns`, and the rest) **must** include a `User-Agent` header. A request without one is rejected with a 403 before it reaches the endpoint logic:

```json
{
  "statusCode": 403,
  "name": "validation_error",
  "message": "All API requests must include a User-Agent header."
}
```

This is confusing because the same request often works from `curl` (which sets a `User-Agent` automatically) but fails from a `fetch`/library call that omits it. The fix is simply to send a descriptive `User-Agent`:

**cURL**

```bash
curl -X POST 'https://api.mailblastr.com/emails' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -H 'User-Agent: my-app/1.0' \
  -d '{
    "from": "you@yourdomain.com",
    "to": "user@example.com",
    "subject": "Hello",
    "html": "<p>Hello</p>"
  }'
```

**Node.js**

```javascript
await fetch('https://api.mailblastr.com/emails', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer mb_xxxxxxxxx',
    'Content-Type': 'application/json',
    'User-Agent': 'my-app/1.0',
  },
  body: JSON.stringify({
    from: 'you@yourdomain.com',
    to: 'user@example.com',
    subject: 'Hello',
    html: '<p>Hello</p>',
  }),
});
```

> **Note:** The public tracking and webhook-ingest paths are exempt — only the management/sending API surface requires a `User-Agent`. See the [User-Agent](https://www.mailblastr.com/docs/api/introduction) note in the API introduction.

## Checklist

1. **Confirm the key permission** — If you are calling a management endpoint, use a `full_access` key. A `sending_access` key sending to `POST /emails` is fine; managing domains/audiences/keys with it returns `422 invalid_access`.
2. **Send a User-Agent header** — If you get a `403 validation_error` mentioning User-Agent, your HTTP client is omitting the header. Add a descriptive `User-Agent` to every request.
3. **Verify the from-domain** — If you are sending and the error is `422 validation_error` about the domain, finish DNS verification first — and make sure the `from` matches your verified domain exactly (subdomain included). That is a separate problem from a permission error.
4. **Check production access** — If sends only work to verified recipients, request production access to leave review mode.
