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

# Error codes & responses

> The response envelope, stable error codes, and how they map to HTTP status codes.

## Response envelope

Every action-style response follows a consistent shape. On success:

```json theme={null}
{ "success": true, "data": { /* … */ } }
```

On failure:

```json theme={null}
{
  "success": false,
  "error": "Variant is required",        // human-readable, for your logs
  "errorCode": "VARIANT_REQUIRED",        // stable, branch on this
  "fieldErrors": [                          // present for input validation
    { "field": "variantId", "code": "VARIANT_REQUIRED" }
  ]
}
```

Responses may also carry `businessRuleWarnings` (when a rule warned but allowed the
action) and `approvalRequested` (when an approval policy intercepted a validation).

**Always branch on `errorCode`, not on the `error` text** — the text is for logs and may
change or be localized; the code is stable.

## HTTP status mapping

Errors are categorized, and the category determines the HTTP status (with a few
per-code overrides):

| Category                    | HTTP  | Examples                                                         |
| --------------------------- | ----- | ---------------------------------------------------------------- |
| Validation                  | `400` | `VALIDATION_ERROR`, `MISSING_REQUIRED_FIELD`, `VARIANT_REQUIRED` |
| Auth                        | `401` | `UNAUTHORIZED`, `FORBIDDEN`                                      |
| Not found                   | `404` | `RECORD_NOT_FOUND`, `PLAN_NOT_FOUND`                             |
| Business                    | `422` | `BUSINESS_RULE_VIOLATION`, `INSUFFICIENT_STOCK`                  |
| Rate limit                  | `429` | `RATE_LIMIT_EXCEEDED`                                            |
| External                    | `502` | `EXTERNAL_SERVICE_ERROR`, `EXTERNAL_SERVICE_TIMEOUT`             |
| Database / Config / Unknown | `500` | `DATABASE_ERROR`, `UNKNOWN_ERROR`                                |

A notable override: `PLAN_ALREADY_VALIDATED` returns **409 Conflict** rather than 422.

## Common error codes

| Code                                  | Meaning                                     | What to do                                           |
| ------------------------------------- | ------------------------------------------- | ---------------------------------------------------- |
| `UNAUTHORIZED`                        | Token missing, invalid, revoked, or expired | Re-authenticate / issue a new token                  |
| `FORBIDDEN`                           | Token lacks the required permission         | Grant the permission on the token; don't retry as-is |
| `VALIDATION_ERROR`                    | Input failed validation                     | Inspect `fieldErrors`; fix the payload               |
| `RECORD_NOT_FOUND` / `PLAN_NOT_FOUND` | Resource doesn't exist (or not in your org) | Verify the id; don't retry                           |
| `BUSINESS_RULE_VIOLATION`             | A business rule blocked the action          | Read the message / warnings; adjust the request      |
| `PLAN_ALREADY_VALIDATED`              | Plan is past the state you're acting on     | Re-fetch the plan's current status                   |
| `RATE_LIMIT_EXCEEDED`                 | Too many requests (if enforced upstream)    | Back off and retry                                   |
| `DATABASE_ERROR` / `UNKNOWN_ERROR`    | Unexpected server error                     | Retry once; escalate if persistent                   |

There are over a hundred specific codes (validation, plan/item operations, file upload,
API tokens, …). Each endpoint documents the ones it can return in the **API Reference**
tab.

## Localized messages

Error codes are decoupled from display text so messages can be shown in the user's
language. In the web app, codes are translated to English or French; integrators should
rely on the **code** and render their own message if needed.
