> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vouchmark.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Status codes and the error response shape you'll see in practice.

Every error response shares the same base shape:

```json theme={null}
{
  "success": false,
  "status": "error",
  "message": "Company not found"
}
```

`message` is human-readable and may change over time. Most errors carry exactly these three fields — there is no top-level machine `error` code, `statusCode`, `timestamp`, or `path` field on a standard error. Branch on the HTTP status code, and on the more specific fields documented below where they apply.

## Validation errors

Requests that fail schema validation return `400` with a `Validation failed` message and an `errors` array of per-field problems:

```json theme={null}
{
  "success": false,
  "status": "error",
  "message": "Validation failed",
  "errors": [
    { "path": "email", "message": "Invalid email" },
    { "path": "password", "message": "String must contain at least 8 character(s)" }
  ]
}
```

## File upload errors

Upload endpoints add a machine-readable `error` field on failures so you can branch programmatically:

```json theme={null}
{
  "success": false,
  "message": "File size too large. Maximum size is 10MB.",
  "error": "FILE_SIZE_LIMIT_EXCEEDED"
}
```

| `error`                     | Status | When                                                                          |
| --------------------------- | ------ | ----------------------------------------------------------------------------- |
| `FILE_SIZE_LIMIT_EXCEEDED`  | 400    | Upload exceeded the endpoint's size cap (10MB or 25MB depending on endpoint). |
| `FILE_COUNT_LIMIT_EXCEEDED` | 400    | Too many files in a multi-upload request.                                     |
| `UNEXPECTED_FILE_FIELD`     | 400    | A file was sent under an unexpected field name.                               |
| `FILE_UPLOAD_FAILED`        | 400    | Generic upload failure — check the files and retry.                           |

Requests whose body itself is too large (not via the upload fields) return `413` with `"File size too large. Maximum allowed size is 50MB."`. Malformed JSON returns `400` with `"Invalid request format."`.

## Status codes

| Status | Meaning                                                                           | Retry?                                                     |
| ------ | --------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| `400`  | Invalid input, failed validation, or a precondition failed                        | No — fix the request.                                      |
| `401`  | Not authenticated, or the access token is missing/expired                         | Refresh the session and retry.                             |
| `402`  | Payment required (payment processing failed)                                      | No — resolve payment.                                      |
| `403`  | Authenticated but not allowed, email not verified, or insufficient wallet credits | No.                                                        |
| `404`  | Resource not found, or not owned by you                                           | No.                                                        |
| `409`  | Conflict (resource already exists, race)                                          | Sometimes.                                                 |
| `413`  | Payload too large                                                                 | No — shrink it.                                            |
| `429`  | Rate limit hit                                                                    | Yes, after `Retry-After`. See [Rate limits](/rate-limits). |
| `500`  | Unhandled server error                                                            | Yes, with exponential backoff.                             |

## Common conditions

The backend throws typed errors that map to these statuses. The `message` text varies; the status code is the stable signal.

| Condition                   | Status | Typical message                                                                                          |
| --------------------------- | ------ | -------------------------------------------------------------------------------------------------------- |
| Email not verified at login | 403    | "Please verify your email before logging in…" (response also carries `data.requiresVerification: true`). |
| Not authenticated           | 401    | "Unauthorized"                                                                                           |
| Insufficient wallet credits | 403    | "Insufficient credits"                                                                                   |
| Resource not found          | 404    | "Company not found", "Webhook subscription not found", etc.                                              |
| Conflict / already exists   | 409    | "Resource already exists"                                                                                |
| Payment processing failed   | 402    | "Payment processing failed"                                                                              |

Some endpoints attach extra context fields under `data` alongside the base shape (for example, login's email-not-verified response includes `data.requiresVerification` and `data.userId`). Read the specific endpoint's reference page for those.
