Developer Manual
Rate Limits & Plans
Programmatic API access is a paid-plan feature. Requests are rate limited per endpoint class, and a daily usage limit is enforced per plan. When you exceed a limit the API returns 429 with a Retry-After header.
Plan requirement
API access is enabled on the Team, Growth, and Enterprise plans (those with apiAccess true). The Starter and Pro plans do not include programmatic API access — calls from an organization without API access return 403 from the plan guard.
403 here means the org's plan lacks API access — distinct from a 403 Insufficient scope, which means the key lacks a required scope. The SDK surfaces both as PermissionError.Rate limiters
Two limiter tiers apply. Write-heavy endpoints use a stricter limiter than read endpoints; exceeding either returns 429.
| Strict limiter | POST /v1/run — the endpoint that triggers orchestration. |
| Standard limiter | Read and management endpoints: GET /v1/runs, /v1/runs/:id, /v1/triage, triage approve/reject. |
| Daily limit | A per-plan daily usage cap is enforced after auth (the dailyLimitGuard). Exhausting it returns 429. |
Handling 429
A 429 response includes a Retry-After header in seconds. Back off for at least that long before retrying.
# A 429 carries Retry-After (seconds).
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json
{ "error": "Rate limit exceeded" }The SDK parses the header into RateLimitError.retryAfter:
import { RateLimitError } from "@eclips/sdk";
try {
await client.runAndWait("ap_specialist", task);
} catch (err) {
if (err instanceof RateLimitError) {
const wait = err.retryAfter ?? 60; // seconds, from Retry-After
await new Promise((r) => setTimeout(r, wait * 1000));
// …then retry
}
}Credits vs. rate limits
Rate limits are about request frequency; credits are about consumption. Running out of credits is a separate condition from being rate limited — check your /v1/usage summary and the response error message to tell them apart.
GET /v1/usage (scope agents:read). On unlimited plans credits_remaining is null.