Rate Limits
API usage is controlled by request rate limits, workspace credits, and concurrent job 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 to inspect the current API key workspace, credits, active job count, concurrency limit, public API rate-limit policy, and key metadata.
curl -s \
-H "Authorization: Bearer $PROTEINIQ_API_KEY" \
"https://proteiniq.io/api/v1/account"Example response:
{
"object": "account",
"workspace": {
"id": "team_123",
"plan": {
"tier": "pro",
"paid": true
},
"credits": {
"available": 500
}
},
"limits": {
"active_jobs": 1,
"concurrent_jobs": {
"max": 3,
"remaining": 2
},
"public_api_rate_limit": {
"limit": 120,
"window_seconds": 60
}
},
"api_key": {
"id": "key_123",
"env": "LIVE",
"prefix": "pq_live_abc123",
"scopes": ["jobs:read", "jobs:write", "files:read", "files:write"]
}
}Request rate limits
Public API routes are rate limited. Rate-limit failures return rate_limited and may include retry headers.
{
"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
The current public API policy is 120 requests per 60 seconds. Status polling, result fetches, tool reads, and other public API requests share this budget for the API key.
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.
Recommended status polling schedule:
| Poll attempt | Delay before next poll |
|---|---|
| 1 | 5 seconds |
| 2 | 10 seconds |
| 3 | 20 seconds |
| 4+ | 30 seconds |
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 faster status updates.
Credits
Paid jobs require enough workspace credits before they start. Use POST /api/v1/jobs/quote to estimate a job before submission.
curl -s -X POST \
-H "Authorization: Bearer $PROTEINIQ_API_KEY" \
-H "Content-Type: application/json" \
"https://proteiniq.io/api/v1/jobs/quote" \
-d '{
"tool": "esmfold",
"input": {
"inputs": [
{
"id": "seqs_1",
"slotId": "protein",
"kind": "protein",
"format": "fasta",
"content": ">seq\nMKT...",
"source": { "type": "text" }
}
]
},
"settings": {}
}'Quote responses include available_credits, billable_credits, and blocking_errors.
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.