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

# Errors

> HTTP status codes, the error response format and how to handle errors.

Every response reports the result on two levels:

* The **HTTP status code** tells the kind of error: is the request invalid (400), is a permission missing (403), does the record not exist (404)?
* **`ResultCode`** tells exactly what went wrong, e.g. `1002` the customer code is already used. All codes are listed on the [Result codes](/en/v1/guides/result-codes) page.

## Error response

<ResponseField name="Success" type="boolean">`false` for errors.</ResponseField>
<ResponseField name="ResultCode" type="string">`0000` on success. On failure, the code of the first error.</ResponseField>
<ResponseField name="Message" type="string">All error messages joined into one text, separated by spaces (English).</ResponseField>
<ResponseField name="Errors" type="array">`Code` and `Message` for each error. Only present on failure.</ResponseField>

If a request has several validation errors, all of them are returned in one response. `ResultCode` is then the code of the first error; check the `Errors` list when you look for a specific error.

```json theme={null}
{
  "Success": false,
  "ResultCode": "1006",
  "Message": "TaxNumber must contain only digits and be 10 (VKN) or 11 (TCKN) characters long. DiscountRate must be between 0 and 100.",
  "Errors": [
    { "Code": "1006", "Message": "TaxNumber must contain only digits and be 10 (VKN) or 11 (TCKN) characters long." },
    { "Code": "1008", "Message": "DiscountRate must be between 0 and 100." }
  ]
}
```

<Tip>
  Base your integration logic on `Code`, not on the `Message` text. Message wording may be improved, but the meaning of a code never changes.
</Tip>

## HTTP status codes

| Code                        | Meaning                                                                                         | What to do                                                                                       |
| --------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `200 OK`                    | Request succeeded                                                                               |                                                                                                  |
| `201 Created`               | Record created. The `Location` header points to the new record                                  |                                                                                                  |
| `204 No Content`            | Delete succeeded, no body                                                                       |                                                                                                  |
| `400 Bad Request`           | Invalid header or body, or a business rule violation                                            | Read the `Errors` list and fix the request. Sending the same request again gives the same result |
| `401 Unauthorized`          | Token missing, invalid or expired                                                               | [Refresh the token](/en/v1/guides/authentication) and retry                                      |
| `403 Forbidden`             | The key lacks the [permission](/en/v1/guides/permissions) for this operation                    | Request the permission                                                                           |
| `404 Not Found`             | Record does not exist, is deleted, or is not [visible](/en/v1/guides/sharing-codes) to the user | Check the ID, the company and the user's sharing codes                                           |
| `429 Too Many Requests`     | [Daily limit](/en/v1/guides/rate-limits) reached                                                | Retry the next day                                                                               |
| `500 Internal Server Error` | Unexpected server error (`0001`)                                                                | Retry after a while. If it persists, contact support                                             |

## Order of checks

If a request has problems at different stages, the errors of the first stage are returned. Checks run in this order:

<Steps>
  <Step title="Token (401)">Is there a token, and are its signature and lifetime valid?</Step>
  <Step title="Headers (400)">Are `X-UserID`, `X-CompanyID` and `X-PeriodID` valid, and is the user assigned to the company?</Step>
  <Step title="Permission (403)">Does the key have the required read or write permission for the module?</Step>
  <Step title="Daily limit (429)">Has today's limit been exceeded?</Step>
  <Step title="Body format (400)">Can the JSON body be read?</Step>
  <Step title="Business rules (400 / 404)">Are the fields valid, and does the record exist and is it visible?</Step>
</Steps>

## Malformed body errors

If the JSON body cannot be read (malformed JSON, an invalid value in a GUID field, text in a number field and so on), the API returns **400** with code `0002`. The message contains the JSON path of the invalid field:

```json theme={null}
{
  "Success": false,
  "ResultCode": "0002",
  "Message": "$.DistrictId: The JSON value could not be converted to System.Nullable`1[System.Guid]. Path: $.DistrictId | LineNumber: 3 | BytePositionInLine: 26.",
  "Errors": [
    {
      "Code": "0002",
      "Message": "$.DistrictId: The JSON value could not be converted to System.Nullable`1[System.Guid]. Path: $.DistrictId | LineNumber: 3 | BytePositionInLine: 26."
    }
  ]
}
```

## Handling errors

```javascript theme={null}
const response = await fetch(url, options);

if (response.status === 401) {
  // Refresh the token and retry the request once
}

const body = response.status === 204 ? null : await response.json();

if (!body?.Success && response.status !== 204) {
  const codes = body.Errors.map((e) => e.Code);

  if (codes.includes("1002")) {
    // Customer code already used: find the existing customer and update it
  }

  throw new Error(`Noyax API ${response.status} [${body.ResultCode}]: ${body.Message}`);
}
```

<Tip>
  Retry only `401` (after refreshing the token), `429` (the next day) and `500`. `400`, `403` and `404` return the same result if the request is repeated unchanged.
</Tip>
