Rate Limiting
WarmHub enforces rate limits on write operations to protect platform stability. Rate limits are applied per-user and per-organization, enforced transactionally inside mutations. Read operations are not rate limited.
How It Works
Section titled “How It Works”Limits are scoped in two ways:
| Scope | Key | Description |
|---|---|---|
| Per-user | User ID | Protects against individual abuse. Applied to repo-scoped writes on the free tier; on paid tiers, the org limit governs instead. Standalone operations (org creation, PAT creation) are always per-user regardless of tier. |
| Per-org | Org ID | Shared budget across all org members. Tier-aware — paid orgs get higher limits. |
Rate-Limited Operations
Section titled “Rate-Limited Operations”Only resource-creating and high-cost write operations are rate limited. Operations on existing resources (pause, revoke, rename, delete) are not — they’re self-limiting since you can only act on what already exists.
| Operation | Scope | Strategy |
|---|---|---|
| Commits (things, assertions) | Per-user + per-org | Token bucket |
| Shape creation | Per-org | Token bucket |
| Subscription creation | Per-org | Token bucket |
| Credential set creation | Per-org | Fixed window |
| Repository creation | Per-org | Fixed window |
| Organization creation | Per-user | Fixed window |
| PAT creation | Per-user | Fixed window |
Tier-Based Limits
Section titled “Tier-Based Limits”All organizations start on the free tier. Limits increase with higher tiers:
| Tier | Commits/min | Repos/hr | Shapes/min | Subscriptions/min | Credentials/hr |
|---|---|---|---|---|---|
| Free | 120 (user) / 600 (org) | 20 | 40 | 20 | 20 |
| Pro | 1,000 (org) | 50 | 60 | 30 | 50 |
| Enterprise | 5,000 (org) | 200 | 200 | 100 | 200 |
On paid tiers, limits are only enforced at the org level.
HTTP 429 Responses
Section titled “HTTP 429 Responses”When a rate limit is exceeded, the API returns HTTP 429 with a RATE_LIMITED error:
HTTP/1.1 429 Too Many RequestsRetry-After: 12Content-Type: application/json
{ "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded" }}The Retry-After header indicates the number of seconds to wait before retrying.
Retry Strategy
Section titled “Retry Strategy”When you receive a 429 response:
- Read the
Retry-Afterheader — wait at least that many seconds before retrying - Use exponential backoff as a fallback if the header is missing
- Don’t retry immediately — rapid retries consume tokens and extend the wait
The SDK classifies RATE_LIMITED errors as retryable:
try { await client.commit.apply('acme', 'world', 'sdk', 'add data', ops)} catch (e) { if (e instanceof WarmHubError && e.kind === 'RATE_LIMITED') { // safe to retry after backoff }}The CLI does not auto-retry on rate limits. If a command fails with RATE_LIMITED, wait and retry manually.
MCP tool errors include backendCode: "RATE_LIMITED" when rate limited. MCP clients should treat this as retryable and apply backoff before retrying the tool call.
What Is Not Rate Limited
Section titled “What Is Not Rate Limited”- All read operations — queries, HEAD, history, search
- Operations on existing resources — pause, resume, delete, rename, revoke
- Internal action lifecycle — lease management, delivery arbitration