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

# Errors

> How the API reports errors and what each status code means.

The API uses standard HTTP status codes and returns a consistent JSON error envelope.

## Error envelope

```json theme={null}
{
  "message": "A human-readable description of what went wrong.",
  "errors": {
    "field_name": [
      "Specific validation message for this field."
    ]
  }
}
```

* `message` — always present. Safe to surface to end users.
* `errors` — present on `422` validation failures. Each key is the offending field; each value is an array of per-field messages.

## Status code reference

| Status            | Meaning                                             | Typical cause                                                                                          |
| ----------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `200`             | OK                                                  | Successful read or mutation.                                                                           |
| `201`             | Created                                             | Resource created (some endpoints use `200` instead — both are success).                                |
| `204`             | No Content                                          | Successful delete or empty result.                                                                     |
| `400`             | Bad Request                                         | Malformed JSON or missing required header.                                                             |
| `401`             | Unauthenticated                                     | Missing or invalid Bearer token.                                                                       |
| `403`             | Forbidden                                           | Token lacks the required ability, or the user has no access to the workspace / resource.               |
| `404`             | Not Found                                           | The resource doesn't exist, has been deleted, or belongs to a workspace your token can't see.          |
| `409`             | Conflict                                            | The resource is in a state that prevents the action (e.g. editing a post that's already `publishing`). |
| `422`             | Unprocessable Entity                                | Validation failed. See the `errors` object for per-field details.                                      |
| `429`             | Too Many Requests                                   | Rate limit hit. See [Rate limits](/api-essentials/rate-limits).                                        |
| `500`             | Internal Server Error                               | Unexpected server error. Safe to retry with backoff.                                                   |
| `502 / 503 / 504` | Bad Gateway / Service Unavailable / Gateway Timeout | Transient infrastructure issue. Retry with exponential backoff.                                        |

## Validation errors

The `422` shape mirrors Laravel's validation output:

```json theme={null}
{
  "message": "The given data was invalid.",
  "errors": {
    "publish_at": [
      "The publish at must be a date after now."
    ],
    "media_content_ids.0": [
      "The selected media content id is invalid."
    ]
  }
}
```

Use the `errors` object to display field-level messages in your UI. The numeric suffixes (e.g. `media_content_ids.0`) indicate which entry in an array failed validation.

## Authentication errors

| `message`                      | What to do                                                                                                                                                                                                 |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Unauthenticated.`             | The `Authorization` header is missing, malformed, or the token has been revoked. Re-check the header and generate a new token if needed.                                                                   |
| `Invalid ability provided.`    | The token is valid but doesn't include the required ability for this endpoint. Create a new token with the right abilities in **User Settings → Login & Security**. See [Authentication](/authentication). |
| `This action is unauthorized.` | The user behind the token has no access to the target workspace or resource. Confirm membership in the dashboard.                                                                                          |

## Resource not found

| Scenario                                        | Status | Notes                                                                                                              |
| ----------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------ |
| The ID is a valid UUID format but doesn't exist | `404`  | The resource was deleted or never existed.                                                                         |
| The ID belongs to a different workspace         | `404`  | We deliberately return 404 (not 403) here to avoid leaking the existence of resources in workspaces you can't see. |
| The ID is malformed                             | `404`  | Validation rejects non-UUID values for `{id}` path parameters.                                                     |

## Publish failures

Posts that successfully reach the API but fail when handed off to the social network surface their error in two places:

1. The post's `status` becomes `failed`.
2. `error_message` on the post contains the network's error description (e.g. "Instagram: Media aspect ratio not supported").

The HTTP response from the original create call was `200` — the failure is reported asynchronously. Always check `status` after creating a post, especially for scheduled posts that publish minutes or days after creation.

## Retrying safely

| Failure type         | Safe to retry?                 | Notes                                                                                                                                                                                                                 |
| -------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `4xx` (except `429`) | No                             | Fix the request before retrying.                                                                                                                                                                                      |
| `429`                | Yes — after `Retry-After`      | See [Rate limits](/api-essentials/rate-limits).                                                                                                                                                                       |
| `5xx`                | Yes — with exponential backoff | Idempotent endpoints (`GET`, `PUT`, `DELETE`) are safe to retry blindly. For `POST` (which is non-idempotent), consider whether a duplicate is acceptable, or check whether the resource was created before retrying. |

## Reporting an error

If you see consistent `5xx` responses or behaviour that looks wrong, email [support@publishbuddy.com](mailto:support@publishbuddy.com) with:

* The endpoint and method
* The approximate timestamp (UTC)
* The `X-Request-Id` header from the failing response, if present
* A redacted dump of the request body (omit your token)

That gives us enough to find the request in our logs.
