# Rate limits, pagination and request limits

Per-token and per-IP rate limits, cursor pagination, result limits and request size caps for both interfaces.

Section: Commerce · Getting started
Canonical URL: https://docs.omniretailconnect.nl/commerce/getting-started/limits

## Rate limits

Both interfaces use two limiters, both per minute. Exceeding either returns `429` with a `Retry-After` header: back off for that many seconds.

*Rate limits*

| Limiter | Key | Default |
| --- | --- | --- |
| `Per IP` | Client IP address (IPv6: the /64 prefix) | 300 requests per minute, counted before authentication, so it also counts requests that end in `401`: a flood of bad tokens from one address can also throttle a valid token from that same address. For the REST API, requests that never reach a route (unknown HTTP methods, malformed or encoded paths) count on this bucket too; on the MCP server `PUT`, `PATCH` and `OPTIONS` are not throttled. For the REST API it covers `openapi.json` too. |
| `Per token` | Token | 60 requests per minute, counted after authentication. |

- Each token has its own bucket, and the REST API bucket of a token is separate from its MCP bucket.
- These are defaults. The shop operator can raise them, so a shop may allow more. Always rely on `Retry-After` rather than a fixed number.
- REST responses also carry the framework's `X-RateLimit-Limit` and `X-RateLimit-Remaining` headers; use `Retry-After` for backing off.

### Write limit

Calls of the MCP [write tools](https://docs.omniretailconnect.nl/commerce/mcp/tools.md#write-tools) and of the REST write endpoints ([products](https://docs.omniretailconnect.nl/commerce/api/product-writes.md), [catalogue structure](https://docs.omniretailconnect.nl/commerce/api/catalogue.md), [discounts](https://docs.omniretailconnect.nl/commerce/api/discounts.md), [orders](https://docs.omniretailconnect.nl/commerce/api/order-writes.md), [pages](https://docs.omniretailconnect.nl/commerce/api/pages.md)) have a third limit: 30 write calls per token per minute, counted on top of the per-token limit and shared by the MCP server and the REST API.

- Over it, a write tool answers the tool error `too_many_requests` and a REST write endpoint `429` `too_many_requests`, with the message `Too many write requests. Try again in a minute.` The call does not run, but it still counts. Do not rely on `Retry-After` here: wait a minute.
- Every write call counts, also one that fails validation.
- The write limit is fixed for an installation; only the general limits above can be raised by the operator.

## Pagination

`GET /products` and `GET /orders` (REST) and the tools `search_products` and `search_orders` (MCP) page with a cursor. There are no totals.

- Pass the next cursor back unchanged as `cursor`, with the same filters, to get the next page. REST: `meta.next_cursor`, with `meta.has_more`. MCP: `next_cursor` and `has_more` next to `items`. The cursor is `null` on the last page.
- Cursors are opaque: never build or edit one. A malformed, tampered or foreign cursor (one issued for another endpoint or tool) is `422` `invalid_argument` over REST and `invalid_argument` ("The cursor is invalid. Start again without a cursor.") over MCP.
- A cursor does not expire and is not tied to a token or to the filters of the original query; presenting it with different filters returns a page of that other query.
- Orders are paged by order id, which stays stable while new orders arrive. Products are paged by result position up to 500; see `truncated` ([REST](https://docs.omniretailconnect.nl/commerce/api/products.md#search-products), [MCP](https://docs.omniretailconnect.nl/commerce/mcp/tools.md#search_products)).

**Walk the order pages**

```bash
# First page, then the next
curl -sS "https://<your-shop-domain>/api/v1/orders?limit=3" \
  -H "Authorization: Bearer $COMMERCE_API_TOKEN"

curl -sS "https://<your-shop-domain>/api/v1/orders?limit=3&cursor=<next_cursor>" \
  -H "Authorization: Bearer $COMMERCE_API_TOKEN"
```

## Result limits

The same limits apply to both interfaces. Out-of-range values are rejected (`422` over REST, `invalid_argument` over MCP), not clamped.

*Default limits*

| Limit | Value |
| --- | --- |
| `Page size` | `limit` is 1 to 50; default 20. |
| `Product paging depth` | Result position 500 (`truncated`). |
| `Date range` | At most 366 days in total for order search and the sales summary. Both days are included, so the end date is at most 365 days after the start date. |
| `Email search window` | At most 90 days in total (both days included) for an order search by email, which also needs `commerce.read.pii`. |
| `SKUs per request` | At most 50 for the availability check. |
| `Variants, images, lines` | A product has at most 100 variants and 10 images. An order has at most 100 lines, 20 shipments and 50 refunds. |
| `Category tree` | Depth 1 to 3 (default 2), at most 500 nodes. |

### Write tool inputs

*Input limits of the write tools*

| Input | Limit |
| --- | --- |
| `Names` | Product and category names at most 255 characters. |
| `Descriptions` | Product and category descriptions at most 5000 characters. |
| `Categories per product` | At most 50 ids in `update_product` `collections`. |
| `Price` | 0 to 100000000 cents. |
| `Stock quantity` | 0 to 1000000. |
| `Image URL` | `https` on a public host, no redirects. See `add_product_media`. |
| `Image download` | At most 10 MB; 5 seconds to connect and 15 seconds in total. |
| `Image size` | At most 8000 pixels on a side and 40 megapixels. |
| `Alternative text` | At most 255 characters. |

## Request size

- **REST:** the URL (path plus query string) may be at most 4096 bytes by default, otherwise the answer is `414` `uri_too_long`. Fifty SKUs of 64 characters need about 3200 characters in the comma form and about 3.5 to 3.9 thousand in the array form, so a full availability request fits; split anything larger. Only the query string is read; a request body is ignored.
- **REST writes:** a JSON body of at most 65536 bytes; the page writes (`POST /pages`, `PATCH /pages/{id}`) take 262144 bytes.
- **MCP:** request bodies above 256 KiB (64 KiB before server version 1.6.0) are refused with `413` before the JSON is decoded or the token is checked. Every tool except `create_page` and `update_page` is still refused above 64 KiB of arguments with `invalid_argument`. A normal tool call is a few hundred bytes.
