# Errors

Standard error response format and all HTTP status codes used by the API.

Source: https://support.toolingmetrics.com/en/api/errors/
Updated: 2026-10-29

Most API errors return a JSON body with an `errors` array. One endpoint category is the exception — read the note on `404` below before you write a generic error parser.

## Error response format

```json
{
  "errors": ["Description of what went wrong"]
}
```

For validation errors on write requests, the errors array contains one message per failing field:

```json
{
  "errors": [
    "Name can't be blank",
    "Quantity must be greater than 0"
  ]
}
```

### The `404` exception

Every "record not found" response (id doesn't exist, or belongs to a different organization) is raised explicitly in each controller's rescue block, and it uses a **singular** `error` key with a string value — not the `errors` array used everywhere else:

```json
{
  "error": "Couldn't find Part with 'id'=999"
}
```

If your error-handling code only checks `body.errors`, it will silently miss `404`s. Check the status code first, and branch on the key when reading `404` bodies specifically.

## HTTP status codes

| Status | Meaning | Common causes |
|---|---|---|
| `200 OK` | Request succeeded | GET, PATCH |
| `201 Created` | Resource created | POST |
| `204 No Content` | Resource deleted | DELETE |
| `401 Unauthorized` | Token missing/invalid, **or** the request is valid but not authorized | Both cases share this status — see [Authentication](https://support.toolingmetrics.com/en/api/authentication/) for how to tell them apart. An `organization_id` that doesn't exist gets the authorization failure too, as an organization you cannot reach. There is no `403` in this API |
| `404 Not Found` | Resource not found | Wrong ID, or resource belongs to a different organization. Body uses the singular `error` key — see above |
| `422 Unprocessable Entity` | Validation failed | Required fields missing, invalid field values |
| `429 Too Many Requests` | Rate limit exceeded | See [Rate limits](https://support.toolingmetrics.com/en/api/rate-limits/) |

`400 Bad Request` and `500 Internal Server Error` can occur (malformed JSON, unexpected server errors) but aren't explicitly handled by the API controllers — don't assume their response body follows the `errors`/`error` shape above.

## Handling errors

```python
import requests

response = requests.get(
    "https://api.toolingmetrics.com/v1/organizations/12/machines",
    headers={"Authorization": "Bearer YOUR_TOKEN"}
)

if response.status_code == 401:
    print("Check your API token, or your role for this resource")
elif response.status_code == 404:
    print("Not found:", response.json().get("error"))
elif response.status_code == 429:
    retry_after = response.headers.get("Retry-After", 60)
    print(f"Rate limited. Retry after {retry_after} seconds.")
elif not response.ok:
    errors = response.json().get("errors", [])
    print("API error:", errors)
else:
    data = response.json()
```
