# Errors and Validation

The Viresso API uses standard HTTP status codes and returns structured error responses.

## HTTP status codes

| Status | Meaning |
|---|---|
| 200 | Success |
| 201 | Created (entry or file) |
| 202 | Accepted (queued pipeline execution) |
| 204 | No Content (successful delete or email API request) |
| 400 | Bad request — invalid parameters or malformed request body |
| 403 | Forbidden — invalid key, origin mismatch, missing ability/permission, or workspace suspended |
| 404 | Not found — workspace, content type, entry, or file does not exist |
| 422 | Unprocessable Entity — validation failed |
| 429 | Too Many Requests — rate limit exceeded |

## Validation errors (422)

When a request fails validation, the API returns a `422` status with details about which fields failed and why:

```json
{
  "message": "The title field is required.",
  "errors": {
    "fields.title": [
      "The title field is required."
    ],
    "fields.slug": [
      "The slug field format is invalid."
    ]
  }
}
```

These are production response examples. Local and test environments can include exception diagnostics on non-validation errors; clients should use HTTP status codes and validation fields instead of matching whole messages.

The `errors` object maps field names to arrays of error messages. Field names use dot notation for nested fields (e.g. `fields.title` for an entry field named `title`).

## Authentication and permission errors (403)

Missing, invalid, revoked, or rotated API keys and origin mismatches return:

```json
{
  "message": "Forbidden"
}
```

A valid key without the required ability or creator permission returns:

```json
{
  "message": "This API key is not permitted to perform this action."
}
```

API keys do not have automatic expiry. Hosted authentication access tokens are separate credentials and cannot be used as API keys.

## Upload validation

File uploads validate the `file` field against the platform's permitted types and maximum size. Missing files, invalid base64, disallowed file types, and files exceeding that limit return `422` with `errors.file`. PHP or the web server may reject oversized requests earlier with `413`, before application validation runs.

Use [Files API](/docs/api/files) for multipart and base64 request formats. An API key with entry-write access alone cannot upload; it also needs `files:write`.

## Not found errors (404)

```json
{
  "message": "Not Found"
}
```

## Rate limiting (429)

When you exceed the rate limit, the API returns:

```json
{
  "message": "Too Many Requests"
}
```

The `Retry-After` header indicates how many seconds to wait before retrying. The defaults below are configurable and are disabled in local/test environments unless `RATE_LIMITING_ENABLED=true`.

### Rate limits

| Endpoint group | Limit and scope |
|---|---|
| Entries | 500 requests per minute per API key |
| File uploads | 60 requests per minute per API key |
| File deletions | 60 requests per minute per API key |
| Tokenized file downloads | 1,200 requests per minute per capability URL |
| Pipeline execution | 30 requests per minute per API key |
| Transactional mail | 10 requests per minute per API key |
| Hosted auth login | 10 requests per minute per email and 60 per IP |
| Hosted auth verification | 10 requests per minute per OTP and 120 per IP |
| Hosted auth token exchange | 60 requests per minute per IP |
| Hosted auth session validation | 600 requests per minute per access token |

## Locale validation errors (400)

Invalid locale codes return `400`. Read endpoints include the locale in the message; write validation may return the generic `Bad Request`:

```json
{
  "message": "No locale found for [xx-XX]."
}
```

## Suspended workspace errors (403)

Requests to a suspended workspace return:

```json
{
  "message": "Workspace suspended."
}
```

See [Workspace Suspension](/docs/platform/workspace-suspension) for details.

## Common validation patterns

| Pattern | Error |
|---|---|
| Missing required field | `The [field] field is required.` |
| Field exceeds max length | `The [field] field must not be greater than [n] characters.` |
| Invalid format | `The [field] field format is invalid.` |
| Unique constraint | `The [field] has already been taken.` |
| Invalid locale | `No locale found for [xx-XX].` |

## Related pages

- [API Overview](/docs/api/overview) — Base URL, headers, and error handling.
- [API Authentication](/docs/api/authentication) — API keys and hosted authentication.
- [Workspace Suspension](/docs/platform/workspace-suspension) — Suspension mechanics.
