> For the complete documentation index, see [llms.txt](https://developerdocs.instructure.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developerdocs.instructure.com/services/mastery-connect/limits-policies.md).

# Rate Limits & Policies

Request budgets, page caps, and the headers that report them.

## Data Endpoints

|          |                                           |
| -------- | ----------------------------------------- |
| Limit    | **300 requests per minute**, per district |
| Window   | 1 minute, rolling                         |
| Scope    | The district, not the credential          |
| Exceeded | `429 Too Many Requests`                   |

The budget belongs to the **district**, so every credential and every process you run draws from the same pool. Two nightly jobs against the same district share 300 requests per minute between them.

At the maximum page size of 100 records, 300 requests per minute is roughly 30,000 records a minute — comfortably more than a well-behaved sync needs.

## Token Endpoint

`POST /api/v2/token` has its own, much tighter limit:

|          |                               |
| -------- | ----------------------------- |
| Limit    | **15 requests per 5 minutes** |
| Keyed on | `client_id` + IP address      |

This exists to blunt credential guessing. Since tokens last two hours, a correct client needs only a handful per day — if you are anywhere near this limit, you are minting a token per request instead of caching one. See [Handling Expiry](/services/mastery-connect/authentication.md#handling-expiry).

## Rate Limit Headers

Successful responses carry your current budget. Both the IETF and the legacy `X-` prefixed families are sent, with identical values; use whichever your HTTP client already understands.

```http
RateLimit-Limit: 300
RateLimit-Remaining: 287
RateLimit-Reset: 1789012800

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1789012800
```

| Header                | Meaning                                |
| --------------------- | -------------------------------------- |
| `RateLimit-Limit`     | Requests allowed in the window.        |
| `RateLimit-Remaining` | Requests left in the current window.   |
| `RateLimit-Reset`     | Unix timestamp when the window resets. |

{% hint style="info" %}
These headers are best-effort. If the counter is briefly unavailable the request still succeeds but the headers may be absent — so treat them as advisory and always handle a `429` regardless of what `RateLimit-Remaining` last said.
{% endhint %}

## Handling a 429

A `429` includes `Retry-After`, in seconds. Wait at least that long:

```python
if response.status_code == 429:
    time.sleep(int(response.headers.get("Retry-After", 60)))
    # then retry
```

Because the window is one minute, `Retry-After` will never exceed \~60 seconds.

## Staying Under the Limit

**Use `page[size]=100`.** The single most effective change: one request for 100 records instead of four for 25.

**Sync incrementally.** Where `filter[updated_since]` is available, fetch only what changed rather than the whole dataset. See [Filtering by Modification Time](/services/mastery-connect/conventions.md#filtering-by-modification-time).

**Cache tokens.** One token serves two hours of requests.

**Serialise your requests.** Parallel workers hit the shared district budget much faster than you would expect. Start sequential and add concurrency only if you need it — while watching `RateLimit-Remaining`.

**Schedule off-peak.** Bulk extracts during the school day compete with teachers using the product.

**Back off on 429, don't retry tightly.** A retry loop with no delay turns one `429` into a sustained block.

## Other Limits

|                   |                                                           |
| ----------------- | --------------------------------------------------------- |
| Maximum page size | 100 records                                               |
| Default page size | 25 records                                                |
| Token lifetime    | 2 hours (or the credential's expiry, whichever is sooner) |

## Data Policies

**Read-only.** `GET` only. No endpoint modifies data.

**District isolation.** A credential reads exactly one district's data. Ids from another district return `404`.

**Withheld data.** Answer keys, correct answers, individual student responses and section SIS identifiers are not exposed by any endpoint at any scope. See [Key Concepts](/services/mastery-connect/key-concepts.md#what-is-deliberately-absent).

**Student data.** Responses may contain personally identifiable student information. Handle it in line with your district's obligations — FERPA and any applicable state privacy law. Encrypt it at rest, restrict access to it, and do not send it to third-party services without the appropriate agreements.

**Auditing.** API access is logged. Requests are attributable to the credential that made them, which is a reason to use separate credentials for separate integrations rather than sharing one.

## Availability

Check [status.instructure.com](https://status.instructure.com/) for incidents. Treat `5xx` responses as transient and retry with exponential backoff.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developerdocs.instructure.com/services/mastery-connect/limits-policies.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
