Limits
Plan limits, the null-means-unlimited convention, and exactly where each ceiling is enforced.
Every organization has a subscription that carries four limits. Knowing which of them block a request — and which are only recorded — saves a lot of debugging.
The four limits
Prop
Type
Read the current values for your organization from GET /v1/profiles/stats, or for every
plan from the public GET /v1/plans.
null means unlimited
Limits use an explicit null = unlimited convention. A custom enterprise plan can set
unlimited profiles and unlimited concurrency and still be metered for visibility.
Treat null as "no ceiling", never as zero.
Where each is enforced
| Limit | Enforced at | Failure |
|---|---|---|
profileLimit | POST /v1/profiles, POST /v1/profiles/:id/duplicate | 403 with AUTHORIZATION_ERROR |
profileLimit (as concurrency) | POST /v1/license/authorize, before every launch | 402 with reason: "concurrency_limit" |
memberLimit | POST /v1/organizations/:id/members/invite | 403 with AUTHORIZATION_ERROR |
apiRpmLimit / apiRphLimit | Not enforced on requests today | — |
Profiles
Creating or duplicating a profile counts the organization's existing profiles first. At
the ceiling, the request fails with a detail object carrying current and limit, so
you can show the user exactly how far over they are.
Concurrency
Concurrency is counted organization-wide, not per host. Before launching, a worker
calls POST /v1/license/authorize; the cloud counts running profile sessions across the
whole organization and compares against the ceiling.
In the shipped implementation the concurrency ceiling is the organization's profile limit. There is no separate concurrency plan field, so a 200-profile plan permits 200 simultaneous browsers.
Authorization is fail-closed: if the cloud denies the request or is unreachable, the worker does not launch. Sessions already running are never killed. See Licensing & concurrency.
API rate limits
RPM and RPH are recorded, not enforced
apiRpmLimit and apiRphLimit are plan metadata. They are stored on the subscription,
surfaced through GET /v1/plans and the dashboard, and used to compute remaining quota
for display — but no middleware currently rejects a request for exceeding them. Do not
design a client that relies on the API throttling you; build your own pacing.
The one place a rate limit is genuinely enforced is the public contact endpoint, which allows five submissions per hour per IP.
Add-ons
Paid plans can extend the base ceilings with add-ons. The effective limit is the plan's base value plus any purchased additions, snapshotted onto the subscription at purchase time:
effective = baseLimit + additionalBecause the base values are snapshotted, a later change to the plan catalog does not
retroactively alter an existing subscription. Both apiRpmLimit and apiRphLimit stay
null when the base is null, regardless of add-ons.
Checking usage
GET /v1/profiles/stats returns current consumption alongside the ceilings:
{
"success": true,
"data": {
"totalProfiles": 143,
"activeProfiles": 12,
"profileLimit": 200,
"memberLimit": 6,
"apiRpmLimit": 100,
"apiRphLimit": 2000
}
}activeProfiles is the number currently running, which is what the concurrency check
compares against.
Next steps
- Errors — the shape of a limit rejection.
- Licensing & concurrency — how limits reach a self-hosted fleet.
- API reference — endpoints that consume quota.