# API errors

> Every error code the Faivelo API returns, what it means and how to fix it.

Every error from the REST API (`/api/v1`) and the partner API (`/api/partner`) has the same shape:

```json
{
  "success": false,
  "error": "This API key is missing the required scope: mail:send",
  "code": "insufficient_scope",
  "fix": "Create a key that includes the \"mail:send\" scope at https://faivelo.com/settings/developers and use it instead; scopes cannot be added to an existing key.",
  "docs": "https://faivelo.com/docs/developers/errors#insufficient_scope",
  "statusCode": 403
}
```

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Meaning
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        code
      </code>
    </td>
    
    <td>
      Stable, machine-readable. Branch on this, never on the message text.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        error
      </code>
    </td>
    
    <td>
      What went wrong, in plain English. May include specifics such as the scope or address.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fix
      </code>
    </td>
    
    <td>
      What to change before trying again.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        docs
      </code>
    </td>
    
    <td>
      A link to the code's entry on this page.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        param
      </code>
    </td>
    
    <td>
      The request field at fault. Only on <code>
        validation_error
      </code>
      
      , and only when one field is to blame.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        statusCode
      </code>
    </td>
    
    <td>
      The HTTP status, repeated for convenience.
    </td>
  </tr>
</tbody>
</table>

Some errors carry extra fields, such as `requiredScope` on `insufficient_scope` and `retryAfter` (seconds) on `rate_limited`. A `429` also sets the `Retry-After` header.

<docs-aside title="Retry or not?" type="tip">

Retry `429` after the wait it names, and `5xx` with backoff. Send the same `Idempotency-Key` on a retried send and it goes out at most once. Every `4xx` other than `429` fails the same way until the request or the account changes: read `fix` first.

</docs-aside>

The SDK (`npm install faivelo`) throws these as `FaiveloError`, with the HTTP status in `statusCode` and the message in `message`.

## Authentication (401)

### `missing_api_key`

`401` · Send the key as "Authorization: Bearer fvl_live_..." (or an "X-API-Key" header). Keys start with fvl_live_; a person on the account creates one at [https://faivelo.com/settings/developers](https://faivelo.com/settings/developers).

### `invalid_api_key`

`401` · The key is unknown or was revoked. Check it was copied in full, or create a new key at [https://faivelo.com/settings/developers](https://faivelo.com/settings/developers).

### `api_key_expired`

`401` · Create a new key at [https://faivelo.com/settings/developers](https://faivelo.com/settings/developers) and replace the expired one.

### `invalid_access_token`

`401` · The OAuth access token (fvl_oat_...) is invalid, expired or revoked. Refresh it with your refresh token, or reconnect the app.

### `unauthorized`

`401` · Authenticate with an API key in the Authorization header: "Bearer fvl_live_...".

## Billing (402)

### `plan_required`

`402` · The account's plan does not include this. A person on the account can upgrade at [https://faivelo.com/billing](https://faivelo.com/billing).

## Permission and account state (403)

### `insufficient_scope`

`403` · The key does not carry the scope this endpoint needs (named in the error). Create a key with that scope at [https://faivelo.com/settings/developers](https://faivelo.com/settings/developers); scopes cannot be added to an existing key.

### `partner_key_not_allowed`

`403` · Partner keys only work on /api/partner/* endpoints. Use an account or agent key (fvl_live_...) for /api/v1.

### `account_paused`

`403` · The partner that manages this account paused it. The partner can resume it from the partner API or console.

### `account_suspended`

`403` · Retrying will not help. The account owner should contact [support@faivelo.com](mailto:support@faivelo.com).

### `sending_paused`

`403` · Sending is paused because recent mail bounced or was reported as spam. Retrying will not help; the account owner should read the email Faivelo sent them or contact [support@faivelo.com](mailto:support@faivelo.com).

### `send_limit_reached`

`403` · The plan's monthly send allowance is used up. Wait for the next billing month or upgrade at [https://faivelo.com/billing](https://faivelo.com/billing).

### `domain_not_on_account`

`403` · Send from an address on a domain this account owns. List them with GET /api/v1/domains.

### `domain_not_verified`

`403` · The sending domain has not passed DNS verification yet. Add the DNS records shown for it in the dashboard (GET /api/v1/domains/{domain} returns its status), then retry once it is verified.

### `shared_domain_phone_required`

`403` · A person on the account must verify a phone number in the dashboard before this free address can send.

### `forbidden`

`403` · The key is valid but not allowed to do this. Check the key kind and scopes, or use a key from the account that owns the resource.

## Request problems (400, 413)

### `validation_error`

`400` · A field in the request is missing or has the wrong type or format (named in "param" when known). Correct it and resend; the API reference at [https://faivelo.com/docs/api](https://faivelo.com/docs/api) lists every field.

### `invalid_sender`

`400` · Use a plain sender like "[hello@yourdomain.com](mailto:hello@yourdomain.com)" or "Name [hello@yourdomain.com](mailto:hello@yourdomain.com)" on a verified domain.

### `idempotency_key_invalid`

`400` · Send an Idempotency-Key of 256 characters or fewer, derived from the event that triggered the send (an order id, not a timestamp).

### `invalid_request`

`400` · The request was malformed. Check it against the API reference at [https://faivelo.com/docs/api](https://faivelo.com/docs/api).

### `attachments_too_large`

`413` · Keep attachments to 10 files and 10 MB in total (before base64), or send a link instead.

### `payload_too_large`

`413` · Send a smaller request body.

## Not found (404)

### `mailbox_not_found`

`404` · Use the full address ([user@yourdomain.com](mailto:user@yourdomain.com)). GET /api/v1/mailboxes lists the mailboxes this key can reach; agent keys only see mailboxes they created or were granted.

### `domain_not_found`

`404` · GET /api/v1/domains lists the domains on this account. Use the bare domain, e.g. "yourdomain.com".

### `alias_not_found`

`404` · GET /api/v1/aliases lists the aliases on this account.

### `email_not_found`

`404` · Use the "id" returned by POST /api/v1/emails. Ids belong to the account that sent the email.

### `template_not_found`

`404` · Check the template alias in the dashboard under Transactional → Templates; aliases are case-sensitive.

### `not_found`

`404` · The resource does not exist or this key cannot see it. Check the path against [https://faivelo.com/docs/api](https://faivelo.com/docs/api).

## Conflicts and refused content (409, 422)

### `idempotency_in_progress`

`409` · A request with the same Idempotency-Key is still running. Wait a few seconds and retry with the same key to get its result.

### `idempotency_key_reused`

`422` · This Idempotency-Key was already used with a different request body. Use a new key for a new request.

### `template_paused`

`409` · Resume the template in the dashboard under Transactional → Templates, or send inline html/text instead.

### `conflict`

`409` · The resource is in a state that does not allow this. Read it again, then retry.

### `missing_template_variables`

`422` · Pass every variable the template uses in "variables" (the missing names are in the error). Nothing was sent.

### `all_recipients_suppressed`

`422` · Every recipient previously hard-bounced or reported spam, so nothing was sent. Remove them from the suppression list in the dashboard only if you are sure the address now works.

### `unprocessable`

`422` · The request was understood but could not be completed. The error says why.

## Limits (429)

### `rate_limited`

`429` · Too many requests for this key (120 per minute). Wait for the Retry-After header (seconds), then retry.

### `mailbox_creation_limit`

`429` · A key may create 10 mailboxes per rolling 24 hours. Reuse an existing mailbox or try again tomorrow.

### `send_rate_limited`

`429` · The plan's sending speed or daily volume is used up. The error says which limit and when it resets; wait that long, or split the recipients across several calls.

### `shared_domain_send_limit`

`429` · Free shared addresses have a small daily send allowance. Wait until tomorrow, or send from your own domain on a paid plan.

## Server (5xx)

### `send_failed`

`502` · The email could not be handed to the mail system. Retry with the same Idempotency-Key; it is safe and sends at most once.

### `internal_error`

`500` · Something went wrong on our side. Retry with backoff; if it persists, email [support@faivelo.com](mailto:support@faivelo.com) with the time of the request.
