# Limits and allowances

> Monthly requests, AI uses and rate limits for REST and MCP clients.

Source: https://workroad.app/docs/api/limits

## Monthly requests on the free plan

On the free plan, the REST API and the MCP server allow 100 requests per UTC calendar month. The count belongs to the user, so every API key and connected app they have takes from the same 100, over REST and MCP alike. WorkRoad Plus and admin accounts have no monthly count, and their responses carry none of the headers below.

Each REST operation and each MCP `tools/call` that runs an operation is one request. A call counts once it gets past the key check, its scopes, the per-key [rate limits](#rate-limits), the `Idempotency-Key` check and input validation, and its operation starts. From then on it counts whatever the operation answers, including a 404, a 409, a 402 `ai_limit_reached`, a 429 from the user's [AI rate limit](#ai-rate-limits) or a 500, and the request is not given back. A call refused before that counts nothing: a 401 or 403, a 429 from the per-key rate limits, an `Idempotency-Key` error, a 400 for invalid input or a 404 for a malformed path id.

These never count:

- MCP protocol messages: `initialize`, `tools/list`, `prompts/list`, `prompts/get`, `resources/list`, `resources/read` and `ping`.
- The docs operations, `GET /docs/search` and `GET /docs/page`, and their MCP tools `searchDocs` and `getDoc`.
- [Test mode](https://workroad.app/docs/api/conventions#test-mode), at `/api/test/v1` and `/api/test/mcp`.
- An [idempotent replay](https://workroad.app/docs/api/conventions#idempotency), a response with `Idempotent-Replayed: true`. A replay is still served after the month's requests are spent.

Once the month's requests are spent, a call that would count returns 402 `api_allowance_reached` and runs nothing. `details` has the `limit`, the requests `used`, `resetsAt`, the start of next month (UTC) as an ISO timestamp, and `upgradeUrl`, the page where the user upgrades:

```json
{
   "error": {
      "code": "api_allowance_reached",
      "message": "This month's 100 free API and AI app requests are used up. They reset on 2026-11-01 (UTC). WorkRoad Plus gives full API and AI app access: https://workroad.app/user/account/plan",
      "details": {
         "limit": 100,
         "used": 100,
         "resetsAt": "2026-11-01T00:00:00.000Z",
         "upgradeUrl": "https://workroad.app/user/account/plan"
      }
   }
}
```

Over MCP the tool call returns a tool error holding the same envelope, so ChatGPT or Claude shows the user the message.

Every counted call of a free account, and every 402 `api_allowance_reached`, carries the month's state:

```http
X-WorkRoad-Allowance-Limit: 100
X-WorkRoad-Allowance-Remaining: 63
X-WorkRoad-Allowance-Reset: 1793491200
```

`X-WorkRoad-Allowance-Remaining` counts the requests left this month, this one already taken. `X-WorkRoad-Allowance-Reset` is the start of next month (UTC) as a Unix timestamp in seconds, the same convention as `X-RateLimit-Reset`. Over MCP the headers are on the HTTP response to the `tools/call`.

Upgrading to WorkRoad Plus lifts the limit from the next call. When Plus ends, the limit applies again from the next call. Only calls made on the free plan are counted, so a plan that lapses mid-month usually starts with none used. If WorkRoad can't reach the counter, calls run uncounted.

A free account can add 1 API key and connect 1 app; WorkRoad Plus allows 10 keys and 20 apps. Keys and connections made earlier, or while the account had Plus, keep working and take from the same 100 requests. Nothing is revoked. Regenerating a key doesn't add one, and reconnecting an app that is already connected isn't a new connection. **Settings → Usage** (`/user/usage`) and the API keys and Connected apps pages under **Settings → Developers** show the month's count.

## AI allowance

Every operation that runs AI counts as one AI use: a copilot message, a generation, a practice test WorkRoad's AI writes (its grading included), or AI grading of the short answers in a `POST /tests/from-questions` test, once per submit. Extracting a document's text is not an AI use, and neither is saving content an agent wrote itself (see [Let your AI do the writing](https://workroad.app/docs/api/copilot-and-generations#let-your-ai-do-the-writing)). The free plan allows 3 AI uses per UTC calendar month. The paid plan has no count limit, only a fair-use limit on recordings. `GET /ai-allowance` returns the plan, this month's uses that the allowance paid for (`used`) and those credits paid for (`creditUses`), the `limit` (`null` on the paid plan) and `resetsAt`, the start of next month.

A use holds its slot from the moment the operation starts, so work still running counts. A job that fails or ends without producing anything gives its slot back. A job you stop with `POST /jobs/{jobId}/cancel` still counts, because the AI work up to the stop already ran.

When the month's uses are gone, an operation that needs one returns 402 `ai_limit_reached` and starts nothing. A refused practice test is not created either. `details.code` is `ai-limit-reached` for the free plan's count or `fair-use-limit` for the paid plan's recording limit, `details.limit` is the limit that was reached, and `details.resetsAt` is when it resets. Submitting a practice test is the exception: a test WorkRoad's AI wrote is still graded, and one saved with `POST /tests/from-questions` goes through and leaves the short answers for the user to mark, as [Practice tests](https://workroad.app/docs/api/study-and-practice#practice-tests) describes.

A copilot message refused with 402 is not saved to its conversation and uses none of the free plan's 10 turns a day, so retrying with new request ids adds nothing to the thread. Once a use is available, sending the same `requestId` again sends the message. When the month's uses and the day's turns are both spent, the copilot returns 402, not 429: the month's limit binds, and `details.resetsAt` says when it lifts.

## Rate limits

You can have 1 enabled, unexpired public API key on the free plan and up to 10 on WorkRoad Plus. Calendar-feed keys do not count toward this cap. Regenerating a key reuses its slot and immediately revokes the previous key, so it works even on a key held beyond the cap. If regeneration fails, the previous key remains valid. Keys held beyond the cap, such as ones made before it or while the account had Plus, keep working, but you must get below the cap before creating another. New credentials start with `wr_live_`; existing unprefixed keys continue to work.

Each key gets 120 reads (`GET` and `HEAD`) and 30 writes (`POST`, `PUT`, `PATCH` and `DELETE`) per 60-second fixed window. REST and MCP calls share these buckets. Requests do not extend the window, so steady clients can continue when it resets without an idle pause. Going over either limit returns 429 `rate_limited` with a `Retry-After` header in seconds. On the free plan, calls also take from the [monthly requests](#monthly-requests-on-the-free-plan).

Responses that get past the scope check carry the state of the bucket they used:

```http
RateLimit-Policy: "rest:v1.read";q=120;w=60
RateLimit: "rest:v1.read";r=117;t=42
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1790000000
```

`r` and `X-RateLimit-Remaining` count the requests left in the window. `t` is the number of seconds until the window resets, and `X-RateLimit-Reset` is the same moment as a Unix timestamp. The bucket is `rest:v1.read` for reads and `rest:v1.write` for writes.

401, 403 and 405 responses have no rate-limit headers, and neither does a 404 for a path with no endpoint, because the API rejects those requests before it counts them.

### AI rate limits

Starting WorkRoad's AI is also limited per user, on top of the monthly [AI allowance](#ai-allowance), and the app's AI features share the same limit.

A refused start returns 429 `rate_limited` with `Retry-After` and `details.reason`: `ai-rate` when the bucket is empty, `ai-busy` when too many of the user's AI jobs are still running. Nothing starts and nothing counts toward the AI allowance. Each key or connected app also gets 10 calls a minute to the operations that run AI, which their pages say. Going over returns 429 with `details.reason` `ai-key-burst`, and its rate-limit headers name the `rest:v1.ai` bucket. Operations that don't run AI, such as creating notes, sets and tasks, use neither limit, only the read and write limits above.

### AI throttling details

Each new AI operation takes tokens from the user's bucket: 6 for a recording, 4 for a note generation or a practice test, 3 for a study set, a document read or a timetable photo, 2 for a tutor turn or a feed batch, and 1 for a copilot turn, AI grading or a small assist such as hints. The bucket refills every hour:

| Plan  | Bucket | Refill per hour | AI jobs running at once |
| ----- | ------ | --------------- | ----------------------- |
| Free  | 8      | 8               | 2                       |
| Plus  | 40     | 60              | 4                       |
| Admin | 200    | 600             | 12                      |

Tokens spent recently are remembered, halving every six hours. Once they pass 3 hours of refill on the free plan, or 4 hours on Plus, the refill slows in proportion to the excess, down to a quarter of its rate. Sending the same `requestId` again replays the first start and costs nothing.

### Calendar subscription limits

Calendar subscription URLs have a separate per-token allowance of 120 reads per 60-second fixed window, shared by all subscribers to that URL. A throttled feed returns 429 with `Retry-After`, not a missing-subscription 404. Retry after the reported wait; the subscription remains valid.
