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

# Error handling

> HTTP status codes returned by the PropOps API, what each code means, common causes, and how to handle errors in your integration code.

All PropOps API errors follow the same JSON structure:

```json theme={null}
{
  "success": false,
  "error": "Human-readable error message"
}
```

Check `success` first. If it is `false`, read `error` for a description of what went wrong. The HTTP status code tells you the category of the problem.

<Tip>
  Monitor the `X-RateLimit-Remaining` header on every response. If it reaches zero, your next request will be rejected with `429`. Back off before you hit the limit rather than after.
</Tip>

***

## Status codes

<AccordionGroup>
  <Accordion title="200 OK — Success">
    The request was processed successfully. The response body contains the requested data or a confirmation message.

    ```json theme={null}
    {
      "success": true,
      "data": { ... },
      "count": 12,
      "message": "Operation completed successfully"
    }
    ```

    No action required.
  </Accordion>

  <Accordion title="400 Bad Request — Invalid parameters">
    The request was malformed. This usually means a required field is missing, a value is the wrong type, or a parameter is out of the accepted range.

    ```json theme={null}
    {
      "success": false,
      "error": "Invalid or missing required parameter: job_id"
    }
    ```

    **What to do:** Check your request body and query parameters against the endpoint documentation. Ensure required fields are present and that values match the expected types (e.g., integers for IDs, valid ISO dates for date fields).
  </Accordion>

  <Accordion title="401 Unauthorized — Not authenticated">
    The request did not include valid authentication credentials, or the session or token has expired.

    ```json theme={null}
    {
      "success": false,
      "error": "Authentication required. Please log in."
    }
    ```

    **What to do:**

    * **Browser clients** — redirect the user to the login page.
    * **Bearer token clients** — your token may have been revoked or expired. Request a new token via `POST /api/security/mobile-auth` and retry the request with the new token.
  </Accordion>

  <Accordion title="403 Forbidden — Insufficient permissions">
    The request was authenticated, but your account does not have the permission required to access this endpoint.

    ```json theme={null}
    {
      "success": false,
      "error": "You do not have permission to perform this action"
    }
    ```

    **What to do:** Call `GET /api/users/permissions` to see which permissions are assigned to your account. Ask your PropOps administrator to grant the missing permission to your role. Each endpoint requires a specific permission key in dot-notation (e.g., `api.jobs.manage.manage`).
  </Accordion>

  <Accordion title="404 Not Found — Resource does not exist">
    The requested resource could not be found. This means the record with the given ID does not exist, has been deleted, or belongs to a different tenant.

    ```json theme={null}
    {
      "success": false,
      "error": "Job not found"
    }
    ```

    **What to do:** Verify the ID or identifier you are using is correct. If you received the ID from a previous API call, the record may have been deleted since then.
  </Accordion>

  <Accordion title="429 Too Many Requests — Rate limit exceeded">
    You have sent too many requests in a short period. The API enforces per-IP and per-account rate limits on all endpoints.

    ```json theme={null}
    {
      "success": false,
      "error": "Rate limit exceeded",
      "message": "Too many requests. Please try again later.",
      "limit": 60,
      "retry_after": 30
    }
    ```

    **What to do:** Read the `Retry-After` header to find out how many seconds to wait before retrying. Implement exponential backoff in your client to avoid repeated 429 responses. Monitor `X-RateLimit-Remaining` on each response to slow down before the limit is reached.

    | Header                  | Value                                    |
    | ----------------------- | ---------------------------------------- |
    | `Retry-After`           | Seconds until you can retry              |
    | `X-RateLimit-Limit`     | Total requests allowed per window        |
    | `X-RateLimit-Remaining` | Requests remaining in the current window |
    | `X-RateLimit-Reset`     | Unix timestamp when the window resets    |

    If your integration legitimately requires a higher rate limit, contact your PropOps administrator — per-endpoint limits are configurable in **Admin → Rate Limiting**.
  </Accordion>

  <Accordion title="500 Internal Server Error — Server-side error">
    An unexpected error occurred on the server. This is not caused by your request.

    ```json theme={null}
    {
      "success": false,
      "error": "An error occurred. Please try again."
    }
    ```

    **What to do:** Retry the request after a short delay. If the error persists, check the PropOps system status at `GET /api/system/status` or contact PropOps support at [support@propops.co.uk](mailto:support@propops.co.uk).
  </Accordion>
</AccordionGroup>

***

## Quick reference

| Status | Meaning           | Action                                |
| ------ | ----------------- | ------------------------------------- |
| `200`  | Success           | Read `data`                           |
| `400`  | Bad request       | Fix request parameters                |
| `401`  | Not authenticated | Re-authenticate                       |
| `403`  | No permission     | Request permission from administrator |
| `404`  | Not found         | Check the resource ID                 |
| `429`  | Rate limited      | Wait for `Retry-After` seconds        |
| `500`  | Server error      | Retry; contact support if persistent  |
