# Errors and limits

Source: https://joinopenfile.com/docs/errors
Index: https://joinopenfile.com/llms.txt

Every failure has the same shape:

```json
{
  "error": {
    "code": "invalid_request",
    "message": "The owner signs in the browser at review_url. The API doesn't take a signature.",
    "param": "signature"
  }
}
```

`message` is plain English and safe to show. Over MCP, the same JSON comes back as the tool result with `isError: true`.

| Status | Code | Means |
| --- | --- | --- |
| 400 | `invalid_request` | An input is missing or wrong. `param` names it. |
| 404 | `not_found` | No such thing, or the token is wrong. |
| 409 | `conflict` | Not allowed now, for example changing a signed application. |
| 429 | `rate_limited` | Too many requests. `retry_after` is in seconds. |
| 502 | `upstream_unavailable` | The USPTO or a website didn't answer. **Nothing was checked**, so don't read it as a clear result. |
| 503 | `offline` | New formations or applications are offline for a moment. |
| 500 | `internal_error` | Something failed on our side. Try again. |

## Rate limits

Per IP address, shared with the website.

| Endpoint | Limit |
| --- | --- |
| `POST /formations`, `POST /applications` | 10 per 10 minutes |
| `PATCH /formations/{id}`, `PATCH /applications/{id}` | 30 per minute |
| `GET /formations/{id}`, `GET /orders/{id}`, `GET /applications/{id}`, `GET /filings/{id}` | 60 per minute |
| `POST /filings/{id}/specimen` | 10 per minute |
| `POST /marks/search` | 20 per minute |
| `POST /marks/alternatives` | 6 per minute |
| `POST /sites/check` | 10 per minute |
| `POST /sites/read` | 12 per minute |
| MCP tool calls | 120 per minute |

`POST /classes/suggest` doesn't fail when you go over 20 a minute: it answers from the offline class list, and `source` says `offline`.

## Retries

Nothing here charges or sends anything, so a retry is safe. Retrying `POST /formations` or `POST /applications` makes a second draft, which does no harm: unsigned drafts expire after 30 days.
