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

# Error handling

> Handle validation, authentication, plan, throttling, and server failures.

PostlyBee uses conventional HTTP status codes. Always inspect both the status code and the JSON response before retrying a request.

## Status codes

| Status | Meaning                                      | Recommended action                                    |
| ------ | -------------------------------------------- | ----------------------------------------------------- |
| `200`  | Request completed.                           | Read the response body.                               |
| `201`  | Resource created or operation accepted.      | Store returned IDs.                                   |
| `400`  | Invalid fields or unsupported operation.     | Correct the request before retrying.                  |
| `401`  | Missing or invalid Bearer token.             | Replace or rotate the API key.                        |
| `403`  | Workspace plan does not allow the operation. | Review workspace billing and limits.                  |
| `429`  | Hourly API limit exceeded.                   | Wait for `Retry-After` before retrying.               |
| `500`  | Unexpected server failure.                   | Retry with backoff and contact support if persistent. |

## Validation errors

Validation errors usually include an array of field messages:

```json theme={null}
{
  "message": ["date must be a valid ISO 8601 date string"],
  "error": "Bad Request",
  "statusCode": 400
}
```

Business-rule errors may use a single string in `message` instead.

## Retry strategy

Retry only transient failures such as `429` and `5xx`. Use exponential backoff with jitter, respect `Retry-After`, and cap the number of attempts. Do not automatically retry `400`, `401`, or `403` responses.

```javascript theme={null}
const retryable = response.status === 429 || response.status >= 500;

if (retryable) {
  const retryAfter = Number(response.headers.get('retry-after') || 1);
  await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
}
```

<Tip>
  Log a request identifier, HTTP method, endpoint, status code, and response
  message. Never log the Authorization header or full API key.
</Tip>
