Errors

All public API errors use one JSON envelope with a stable code and message.

ProteinIQ API errors use a consistent JSON envelope. Clients should branch on error.code, not on the human-readable message.

Error envelope

JSON
{
  "error": {
    "code": "validation_error",
    "message": "Invalid request data",
    "details": {}
  }
}

The details field is included only when the route has structured details to return.

Error codes

CodeHTTP statusMeaning
invalid_json400The request body is not valid JSON
validation_error400The request body, query, cursor, or route input is invalid. Job input errors include the rejected path and the canonical input format.
unauthorized401The API key is missing, malformed, expired, revoked, or invalid
insufficient_credits402The workspace does not have enough credits for the requested job
paid_plan_required402The requested action requires an active paid workspace plan
daily_limit_exceeded402The workspace reached a daily submission limit
concurrent_job_limit_exceeded402The workspace has too many active jobs
forbidden403The key is valid but lacks access or the required scope
user_not_found404The user associated with the API key no longer exists
team_not_found404The workspace associated with the API key no longer exists
not_found404The resource does not exist in the API key workspace
method_not_allowed405The route does not support the HTTP method
conflict409The request conflicts with the current resource state
job_not_completed409Results were requested before a job reached a result-ready state
payload_too_large413The request body is too large
unsupported_media_type415A JSON route was called without Content-Type: application/json
rate_limited429The request exceeded the public API rate limit
internal_error500The request failed unexpectedly

Handling errors

  • Retry rate_limited: Respect Retry-After and the rate-limit reset headers when present.
  • Retry transient internal_error responses carefully: Use Idempotency-Key when retrying job submissions.
  • Do not retry validation_error unchanged: Inspect the request shape, tool input contract, and field names.
  • Rebuild rejected job inputs from the tool contract: Mixed canonical and retired fields are rejected. Send only input.inputs[] entries with slotId, kind, format, content, and source.
  • Treat not_found as workspace-scoped: A job outside the API key workspace returns not_found.
  • Handle job_not_completed by waiting: Poll status or use the events endpoint before fetching results again. When Retry-After is present, wait that many seconds before retrying the result endpoint.

JavaScript example

JavaScript
const response = await fetch("https://proteiniq.io/api/v1/jobs", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PROTEINIQ_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "fold-lysozyme-001",
  },
  body: JSON.stringify({
    tool: "esmfold",
    name: "Lysozyme ESMFold run",
    input: {
      inputs: [
        {
          id: "seqs_1",
          slotId: "protein",
          kind: "protein",
          format: "fasta",
          content: ">seq\nMKT...",
          source: { type: "text" },
        },
      ],
    },
    settings: {},
  }),
});

const payload = await response.json();
if (!response.ok) {
  switch (payload.error.code) {
    case "rate_limited":
      throw new Error("Wait before retrying");
    case "validation_error":
      throw new Error(`Fix request: ${payload.error.message}`);
    default:
      throw new Error(`${payload.error.code}: ${payload.error.message}`);
  }
}