# Limits & plans

> Plan limits for operations, agents working at once, spaces, active runs and tasks, request rate, payload size and retention, plus per-space limits and hard API bounds.

Source: https://docs.getrunstate.com/limits/

## Plans

Every limit in this table is counted across the whole organization, not per space, so splitting work into more spaces never buys more capacity. During the developer preview, new organizations start on the Free plan. There is no self-serve upgrade yet; talk to us to change plans.

| | Free | Builder | Team | Scale | Enterprise |
| --- | --- | --- | --- | --- | --- |
| Operations per month | 100,000 (hard stop) | 2,000,000 | 15,000,000 | 100,000,000 | custom |
| Agents working at once | 10 | 100 | 1,000 | 5,000 | custom |
| Spaces | 2 | 10 | unlimited | unlimited | custom |
| Active runs | 200 | 1,000 | 10,000 | 50,000 | custom |
| Active tasks (pending or running) | 1,000 | 10,000 | 100,000 | 500,000 | custom |
| API keys (not revoked) | 10 | 25 | 100 | 500 | custom |
| Requests per minute (whole organization) | 600 | 1,500 | 3,000 | 20,000 | custom |
| Payload size per message | 64 KiB | 64 KiB | 64 KiB | 64 KiB | 64 KiB |
| Data retention | 7 days | 14 days | 30 days | 90 days | custom |

Organizations created before plans existed are on a legacy Preview plan: 3 spaces, 200 active runs, 1,000 active tasks, 10 keys, 600 requests per minute, 64 KiB payloads, 7-day retention, and no cap on operations or agents working at once.

### Operations

An operation is a successful call that changes state: claiming, releasing, sending, receiving a message, completing, submitting, acquiring and so on. These are never counted:

- lease renewals,
- reads (status, lists, events, watch, diagnostics),
- polls that return nothing,
- failed calls,
- idempotent replays of work that already happened.

On the Free plan, new work is refused with `OPERATIONS_EXHAUSTED` once the month's operations are used; work already running can still finish. Paid plans are tracked, not blocked.

### Agents working at once

This counts live leases across the organization: held claims, received messages being worked on and held pool units. It's a soft limit (counts are cached briefly), so treat it as "about" the number shown. Going over returns `CONCURRENCY_LIMITED`; waiting claim and pool acquisitions retry it automatically.

### Request rate

The plan's requests per minute are counted across the whole organization; going over returns `SERVICE_RATE_LIMITED` until the next minute. Part of that capacity is reserved for recovery calls (renew, release, retry, complete, cancel, detach, ack), so new work can't starve the calls agents use to hand work back. Each space also has its own `requestsPerMinute` limit, 600 by default, which returns `RATE_LIMITED`; see [per-space limits](#per-space-limits).

### Retention

Task results, message payloads and finished messages are kept for the plan's retention window. After that a task is tombstoned: its state and reason stay readable and its outcome is cleared. The event journal is kept for the longer of the plan window and 30 days. Audit events are kept for 365 days and usage records for 400 days regardless of plan.

## Per-space limits

Each space also has operational limits, readable with `GET /v1/spaces/{spaceId}/limits` and adjustable with `PUT` (key permission `resource_config`):

| Limit | Default | Allowed | Notes |
| --- | --- | --- | --- |
| `requestsPerMinute` | 600 | 1–100,000 | Can't exceed the plan's requests per minute. Exceeding it returns `RATE_LIMITED`. |
| `maxBacklog` | 1,000 | 1–1,000,000 | Queued plus in-progress messages across the space. Exceeding it returns `BACKLOG_FULL`. |
| `maxPayloadBytes` | 65,536 | 1–65,536 | Can't exceed the plan's payload size. |
| `maxLeaseSeconds` | 600 | 5–600 | |
| `maxPendingWaiters` | 10,000 | 1–1,000,000 | |
| `maxArmedTimers` | 10,000 | 1–1,000,000 | |

The space request rate starts at 600 per minute on every plan. If your plan allows more, raise `requestsPerMinute`:

```bash
curl -X PUT "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/limits" \
  -H "Authorization: Bearer $RUNSTATE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"requestsPerMinute": 1500, "maxBacklog": 10000}'
```

A value above the plan ceiling returns `ENTITLEMENT_EXCEEDED`.

## API bounds

Fixed bounds enforced on requests:

| What | Bound |
| --- | --- |
| Claim key, task key, `workKey`, usage key | 1–512 characters |
| Lease length (`leaseSeconds`) | 5–600 seconds, default 30 |
| Child runs per run (`childLimit`) | 1–10,000, default 1,000 |
| Work queue backlog (`backlogLimit` on create) | 1–100,000, default 1,000 |
| Requirements per task | up to 4 pools and 4 quotas |
| Members per task group | 100 |
| Task group `threshold` | 1–1,000 |
| Quota cooldown | 1–3,600 seconds |
| Quota waiter time-to-live | 5–3,600 seconds |
| Budget currency / scale | 3 letters / 0–9 decimal places |
| Budget amounts | up to 18 digits in minor units |
| Events page (`limit`) | up to 500, default 100 |
| Watch hold (`waitSeconds`) | 0–30 seconds |
| `Idempotency-Key` replay window | 24 hours |
| Queue attempts before a task fails | 5 |

## Service status

The hosted service is a developer preview in a single EU region, without an SLA.
