Reference
Rate limits
Pace requests and plan around workspace compute limits.
ProteinIQ uses several controls for public API usage. Request rate limits protect the API, while credits and job concurrency control compute usage.
Account endpoint
Use GET /api/v1/account with jobs:read to inspect the current API key workspace, credits, active job count, concurrency limit, public API rate-limit policy, and key metadata.
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $PROTEINIQ_API_KEY" \
"https://proteiniq.io/api/v1/account"Abbreviated example response with illustrative credit and concurrency values. RESEARCHER is the API tier identifier for Pro:
{
"object": "account",
"workspace": {
"id": "team_123",
"plan": {
"tier": "RESEARCHER",
"paid": true
},
"credits": {
"available": 500
}
},
"limits": {
"active_jobs": 1,
"concurrent_jobs": {
"max": 10,
"remaining": 9
},
"public_api_rate_limit": {
"limit": 120,
"window_seconds": 60
},
"public_api_workspace_rate_limit": {
"limit": 300,
"window_seconds": 60
}
},
"api_key": {
"id": "key_123",
"env": "LIVE",
"prefix": "pq_live_abc123",
"scopes": ["jobs:read", "jobs:write", "files:read", "files:write", "projects:read", "projects:write"]
}
}Request rate limits
Public API routes are rate limited. Rate-limit failures return rate_limited and may include retry headers.
Authenticated requests use the plan's per-key and workspace budgets. A separate ceiling of 3,000 requests per minute per IP protects authentication while allowing multiple keys and workspaces behind the same shared network.
{
"error": {
"code": "rate_limited",
"message": "Too many requests"
}
}When headers are present, use them to schedule retries:
X-RateLimit-Limit: Current request limitX-RateLimit-Remaining: Remaining requests in the current windowX-RateLimit-Reset: ISO 8601 timestamp for the next resetRetry-After: Suggested seconds to wait before retrying
Each API key has a request budget, and every key in a workspace also shares one workspace budget, so creating more keys does not add capacity. Both depend on the workspace plan and reset every 60 seconds. Status polling, result fetches, tool reads, MCP calls, and other public API requests count toward both budgets. GET /api/v1/account returns the current values.
| Plan | Requests per key | Requests per workspace |
|---|---|---|
| Free | 30 | 60 |
| Lite | 30 | 60 |
| Plus | 60 | 150 |
| Pro, Teams, Enterprise | 120 | 300 |
Free workspaces cannot create API keys. Their budgets apply to MCP connections that sign in with OAuth, where each connection counts as one key.
The per-key budget is sized for polling every running job once every 5 seconds. A separate pre-authentication limit of 120 requests per 60 seconds applies to each IP address.
Operations that do more work have their own workspace limits on top of the request budgets:
| Operation | Free, per workspace per 60 seconds | Paid plans, per workspace per 60 seconds |
|---|---|---|
| Job submissions and workflow starts | 5 | 30 |
| Job quotes | 10 | 30 |
| Event streams opened | 5 | 20 |
| File uploads | 5 | 20 |
Retrying a job submission with the same Idempotency-Key returns the original job and does not count as a new submission.
Job status and result polling also have per-job throttles. For a single API key and job, call GET /api/v1/jobs/{jobId}/status no more than once every 5 seconds. The result endpoint uses the same 5 second per-job pace to protect stored outputs and signed file URL generation.
Polling and backoff
Polling should be paced by job state, not by a fixed sub-second interval. Start status polling at 5 seconds, double the delay after each non-terminal response, and cap the delay at 30 seconds. Add a small random jitter before each poll.
Use delays of 5, 10, 20, and then 30 seconds between polls. A Retry-After value takes precedence even when it exceeds the 30-second backoff cap.
Clients that poll every 0.5 seconds can use the full public API quota on one job and may be throttled by the per-job polling limit. That leaves no room for result fetches, list calls, retries, or other jobs. Use server-sent events when you need live status updates.
Credits
Paid jobs require enough workspace credits for the fixed charge or initial time-based authorization. Quote the job to inspect available_credits, billable_credits, and blocking_errors before submission.
A quote does not reserve credits. Other jobs can spend the balance before a new submission is accepted. Time-based jobs can also request further authorization while they run, subject to their spending limit.
Concurrent jobs
Workspaces have a maximum number of active concurrent jobs. GET /api/v1/account returns the current active count and remaining concurrency.
If the workspace already has too many active jobs, submission can return concurrent_job_limit_exceeded.
Retry behavior
- Rate limit reached: Wait until the reset time before retrying.
- Job still running: Continue polling status with exponential backoff, or use the events endpoint.
- Result not ready: Respect the
Retry-Afterheader before fetching results again. - Concurrent job limit reached: Wait until an active job finishes, then submit again.
- Insufficient credits: Add credits or lower job size before retrying.
- Unknown submission result: Retry with the same
Idempotency-Keyto avoid duplicate jobs.