# Rate limits and throughput
Source: https://www.desktopaccountingapi.com/docs/guides/rate-limits/

> Project rate limits, per-connection queue limits, how QuickBooks itself limits throughput, and how to handle 429 responses.

Two limits protect the service, and one limit comes from QuickBooks itself. In practice the QuickBooks limit is the one you notice.

## Project rate limit

Each project can make **1,000 requests per 10 seconds**, across all its keys and end users. Above that, the API returns `429 RATE_LIMITED` with `details.scope: "project"` and a `Retry-After` header in seconds. Nothing was queued, so the request is safe to retry after the wait.

Every authenticated response carries `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` (seconds) and `RateLimit-Policy: 1000;w=10`. The limit is enforced across our edge network, so `Remaining` and `Reset` are estimates from the server that answered. Treat a `429` with `Retry-After` as authoritative.

## Per-IP limits

Two limits protect against abuse before a key is even checked: 2,000 requests per 10 seconds from one IP address, and 20 failed authentications per minute from one IP address, after which that address is refused for 60 seconds. Both return `429 RATE_LIMITED` with `details.scope: "ip"`. A correctly configured server never meets them.

## Per-connection queue limits

Each connection (one company file) accepts:

- at most **200 pending requests** (queued, waiting or sent), and
- at most **50 sync callers waiting** at the same time.

Beyond either limit, the API returns `429 CONNECTION_QUEUE_FULL` with `details.reason` (`pending_requests` or `sync_waiters`). Nothing was queued. This usually means a loop is sending requests faster than QuickBooks can answer them. Async requests do not count toward the sync waiter limit, so batches belong in async mode.

## QuickBooks throughput

QuickBooks Desktop processes one request at a time for each company file, on your customer's computer. A simple read in a warm session takes well under a second; a large report can take minutes. So:

- **Parallelize across end users, not within one.** Requests for different company files run independently. Sending ten parallel requests for one file only lengthens its queue.
- **Ask for more per request.** Use `limit` up to 150 on cursor lists, and filters such as `updatedAfter`, instead of retrieving records one by one.
- **Use async mode for batches.** Queue the writes with `Prefer: respond-async` and let [webhooks](https://www.desktopaccountingapi.com/docs/guides/webhooks/) tell you as each one completes. The queue keeps order, and your workers do not sit on open HTTP calls.
- **Keep the session warm.** A request sent within about 2 seconds of the previous one finishing reuses the open QuickBooks session and skips the Web Connector check-in.

## Handling 429

The SDKs retry `429` responses automatically, waiting for `Retry-After`, up to their retry limit (two retries by default). For raw HTTP:

1. Read `Retry-After` and wait that many seconds.
2. Retry the same request. For writes, reuse the same `Idempotency-Key`.
3. If you keep hitting `CONNECTION_QUEUE_FULL` for one end user, reduce that end user's concurrency rather than retrying harder.

## Other size limits

| Limit | Value | Error |
| --- | --- | --- |
| Request body | 20 MiB | `413 PAYLOAD_TOO_LARGE` |
| Values in one array query parameter | 100, unless the operation says otherwise | `400 INVALID_PARAMETER` |
| Page size on cursor lists | 1 to 150 | `400 INVALID_PARAMETER` |
| Sync wait (`Daapi-Timeout-Seconds`) | 1 to 300 seconds | `400 INVALID_PARAMETER` |
| Async queue lifetime (`Daapi-Queue-Ttl-Seconds`) | 10 to 86400 seconds | `400 INVALID_PARAMETER` |
| QuickBooks response | Very large unpaged responses | `422 QBD_RESPONSE_TOO_LARGE` |
