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.

Bash
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:

JSON
{
  "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.

JSON
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests"
  }
}

When headers are present, use them to schedule retries:

  • X-RateLimit-Limit: Current request limit
  • X-RateLimit-Remaining: Remaining requests in the current window
  • X-RateLimit-Reset: ISO 8601 timestamp for the next reset
  • Retry-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.

PlanRequests per keyRequests per workspace
Free3060
Lite3060
Plus60150
Pro, Teams, Enterprise120300

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:

OperationFree, per workspace per 60 secondsPaid plans, per workspace per 60 seconds
Job submissions and workflow starts530
Job quotes1030
Event streams opened520
File uploads520

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-After header 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-Key to avoid duplicate jobs.