# Errors and rate limits

> For AI agents: this page is also Markdown at [/developers/errors-and-rate-limits.md](https://www.hsatrackr.com/developers/errors-and-rate-limits.md). Every docs page is listed in [/developers/llms.txt](https://www.hsatrackr.com/developers/llms.txt).

Status codes, the error body, and how the 30 requests per minute limit works.

Errors return JSON with a message and the same disclaimer and docs link as successes:

```json
{
  "error": "Expense \"not-a-real-slug\" not found",
  "meta": {
    "disclaimer": "This information is for educational purposes only and does not constitute tax, legal, or financial advice. Consult a qualified professional for your specific situation.",
    "api_docs": "https://www.hsatrackr.com/api/v1"
  }
}
```

| Status | When |
| --- | --- |
| `400` | A required parameter is missing, or a number is outside the range shown on the endpoint's page. The message names it. |
| `404` | The slug does not exist, or `/limits` has no data for that year. List endpoints return valid slugs. |
| `429` | Over 30 requests in a minute from one IP. This body is only `{ error }`. |

## Inputs that do not error

Some inputs are handled quietly instead of returning 400. Check for them on your side:

- An unknown `category`, `eligibility` or `search` value returns an empty list.
- A number that is not a number (`contribution=abc`) uses the default shown on the endpoint's page.
- `limit` outside 1 to 100 is clamped. A negative `offset` becomes 0.
- Unknown provider slugs in `/providers/compare` are listed in `invalidSlugs`; the call fails only when fewer than two are valid.
- `limits?year=abc` returns every year, and `eligible?limit=abc` returns every match.
- Form 8889 flags such as `age55` are true only when set to `true`. Negative dollar amounts are not rejected.
- A year with no IRS limits is a 404 on `/limits` but a 400 on `/calculator/form-8889`.

## Rate limits

Each IP gets 30 requests per minute across all endpoints. Successful responses send `RateLimit-Limit` and `RateLimit-Policy: 30;w=60`. A 429 also sends `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` in seconds.

Responses are cacheable for a day (`Cache-Control: public, max-age=86400`), so cache on your side before you reach the limit. Need more? Email [support@hsatrackr.com](mailto:support@hsatrackr.com).
