ProteinIQ
DocumentationAPI referenceChangelog
Talk to usGet started

Jobs

Quote, submit, and follow individual tool runs.

A job is one execution of a tool with specific inputs and settings. API jobs use the same workspace credits, permissions, limits, and result storage model as jobs created in the web app.

Quote a job

Use POST /api/v1/jobs/quote with jobs:write to validate a payload and estimate credits without creating a job.

Bash
curl --fail-with-body --silent --show-error -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": ">example\nACDEFGHIKLMNPQRSTVWY",
          "source": { "type": "text" }
        }
      ]
    },
    "settings": {}
  }'

Quote responses include credit estimates, available credits, blocking_errors, current limits, and billing mode. Resolve blocking errors before submission. The values below are illustrative; use your response for current costs and limits. Quotes are optional estimates. They do not reserve credits or retain a prepared submission.

JSON
{
  "object": "job_quote",
  "tool": "esmfold",
  "estimated_credits": 50,
  "available_credits": 500,
  "billable_credits": 50,
  "blocking_errors": [],
  "limits": {
    "active_concurrent_jobs": 0,
    "max_concurrent_jobs": 3,
    "daily_limit_used": 2,
    "daily_limit_max": 100
  },
  "billing": {
    "mode": "fixed"
  }
}

Submit a job

Use POST /api/v1/jobs with jobs:write to create a job. Direct submissions require JSON with tool, name, and input; settings, billing, and project_id are optional. Assigning a project also requires projects:write.

Quote and submission bodies are limited to 512 KiB. After resolving saved file references, combined input content is limited to 50 MiB. Upload larger inputs and reference them with source.file_id; that also requires files:read.

JSON
{
  "tool": "esmfold",
  "name": "ESMfold API example",
  "input": {
    "inputs": [
      {
        "id": "seqs_1",
        "slotId": "protein",
        "kind": "protein",
        "format": "fasta",
        "content": ">example\nACDEFGHIKLMNPQRSTVWY",
        "source": { "type": "text" }
      }
    ]
  },
  "settings": {}
}

Set PROTEINIQ_RUN_KEY to a unique value for each intended analysis, as in the quickstart. Send it as Idempotency-Key or X-Idempotency-Key when submitting or retrying. The same key is scoped to the workspace. Retry with the same request body and key. Changed input, settings, or credit limits require a new key.

To protect against a price increase after quoting, include max_quoted_credits in the submission body. This nonnegative integer limits the fixed charge or initial runtime reservation. If the current amount exceeds it, submission returns 409 with price_changed before creating or charging a job. For runtime billing, billing.max_reserved_credits separately limits the total reservation; max_quoted_credits is not a total runtime budget.

Bash
curl --fail-with-body --silent --show-error -X POST \
  -H "Authorization: Bearer $PROTEINIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $PROTEINIQ_RUN_KEY" \
  "https://proteiniq.io/api/v1/jobs" \
  -d '{
    "tool": "esmfold",
    "name": "ESMfold API example",
    "input": {
      "inputs": [
        {
          "id": "seqs_1",
          "slotId": "protein",
          "kind": "protein",
          "format": "fasta",
          "content": ">example\nACDEFGHIKLMNPQRSTVWY",
          "source": { "type": "text" }
        }
      ]
    },
    "settings": {}
  }'

Submit returns a job resource with status code 202 for new jobs. Replayed idempotent submissions return the stored response status and include a top-level message such as Duplicate suppressed via idempotency key; that replay-only field is not present on status, list, or result resources.

Input validation

Both quote and submit requests accept only input.inputs[]. Each item must include id, slotId, kind, format, content, and source. A saved file reference may omit content only when its file source includes file_id or fileId.

Unknown fields and retired input shapes are rejected, including requests that mix valid canonical inputs with retired fields. For example, this request is rejected:

JSON
{
  "tool": "esmfold",
  "name": "Invalid input example",
  "input": {
    "molecules": []
  },
  "settings": {}
}

The API returns a path-specific response before pricing or job creation:

JSON
{
  "error": {
    "code": "validation_error",
    "message": "input.molecules: unsupported legacy field \"molecules\"; send input.inputs[] with slotId, kind, format, content, and source"
  }
}

Do not remove only the reported field from a mixed payload. Rebuild the request from the active input.slots[] contract returned by the tool endpoint.

Job resource

Single-job endpoints return this resource shape:

JSON
{
  "id": "job_123",
  "object": "job",
  "project_id": "project_123",
  "status": "PROCESSING",
  "tool": "esmfold",
  "name": "ESMfold API example",
  "credits_used": 50,
  "created_at": "2026-06-12T08:00:00.000Z",
  "started_at": "2026-06-12T08:00:02.000Z",
  "completed_at": null,
  "progress": 40,
  "execution_time_seconds": null,
  "error": null,
  "billing": {
    "mode": "fixed",
    "reserved_credits": null,
    "final_credits": null,
    "rate_credits_per_minute": null,
    "billable_runtime_seconds": null,
    "outcome": null,
    "finalized_at": null
  }
}

The billing object is included when billing metadata exists for the job.

List jobs

GET /api/v1/jobs lists jobs in the API key workspace.

Bash
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $PROTEINIQ_API_KEY" \
  "https://proteiniq.io/api/v1/jobs?limit=20"

List jobs supports:

  • limit: Integer from 1 to 100, defaults to 20
  • starting_after: Cursor returned as next_cursor from a previous page
  • project_id: Return jobs assigned to one project
  • unassigned: Set to true to return jobs without a project

Do not combine project_id and unassigned=true.

The response is ordered by newest job first.

JSON
{
  "object": "list",
  "data": [],
  "has_more": false,
  "next_cursor": null
}

Get job status

Status and list requests require jobs:read.

GET /api/v1/jobs/{jobId}/status returns the current job resource.

Bash
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $PROTEINIQ_API_KEY" \
  "https://proteiniq.io/api/v1/jobs/job_123/status"

Poll while the status is PENDING, QUEUED, PROCESSING, or RETRY.

Terminal statuses describe different outcomes:

  • COMPLETED: The job finished successfully.
  • FAILED: The job failed; inspect error and any available partial results.
  • TIMEOUT: The job exceeded its allowed time.
  • CANCELLED: The job was canceled.
  • BUDGET_EXCEEDED: A spending or runtime limit stopped the job; partial outputs may be available.

A terminal status does not guarantee downloadable output. Follow the result availability rules.

Share a job

GET /api/v1/jobs/{jobId}/share returns the current sharing settings for a job in the API key workspace. The endpoint requires jobs:read.

Bash
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $PROTEINIQ_API_KEY" \
  "https://proteiniq.io/api/v1/jobs/job_123/share"

The response includes the job visibility and invited email shares.

JSON
{
  "object": "job_sharing",
  "job_id": "job_123",
  "visibility": "INVITED",
  "shares": [
    {
      "id": "share_123",
      "object": "job_share",
      "email": "collaborator@example.com",
      "claimed": true,
      "claimed_at": "2026-06-12T08:01:00.000Z",
      "invitee_name": "Collaborator",
      "created_at": "2026-06-12T08:00:00.000Z"
    }
  ]
}

PATCH /api/v1/jobs/{jobId}/share updates the same sharing settings available in the web app. The endpoint requires jobs:write, and the API key creator must have permission to update the job.

Bash
curl --fail-with-body --silent --show-error -X PATCH \
  -H "Authorization: Bearer $PROTEINIQ_API_KEY" \
  -H "Content-Type: application/json" \
  "https://proteiniq.io/api/v1/jobs/job_123/share" \
  -d '{
    "visibility": "INVITED",
    "add_invites": ["collaborator@example.com"],
    "remove_invites": ["old-collaborator@example.com"]
  }'

Visibility values are:

  • PRIVATE: Keeps access within normal workspace job permissions
  • PUBLIC: Allows anyone with the job link to view the job
  • AUTHENTICATED: Allows any signed-in ProteinIQ user to view the job
  • INVITED: Allows invited email addresses to view the job, alongside normal workspace job permissions

Update fields are:

  • visibility: One of PRIVATE, PUBLIC, AUTHENTICATED, or INVITED
  • add_invites: Array of email addresses to add to the invited list
  • remove_invites: Array of email addresses to remove from the invited list

New invitations can be added only when the job is already INVITED or the same request sets visibility to INVITED. ProteinIQ normalizes invitation addresses and emails each newly invited person a direct result link.

Snake_case field names are preferred. The API also accepts addInvites and removeInvites aliases for clients that share request code with the web app.

Polling strategy

Use exponential backoff when polling job status. Start with a 5 second delay, then increase to 10 seconds, 20 seconds, and cap at 30 seconds. Add a small random jitter so many jobs submitted at the same time do not poll in lockstep. When a response includes Retry-After, wait at least that many seconds before the next request.

Do not poll /status faster than once every 5 seconds for the same job. Fast polling does not make a job finish sooner, counts against the public API rate limit, and may return rate_limited. For near-real-time updates, use job events.

Fetch results after an eligible terminal state: COMPLETED, BUDGET_EXCEEDED, or FAILED with stored output. If a result request returns job_not_completed, wait for the Retry-After value before trying again.

Cancel a job

POST /api/v1/jobs/{jobId}/cancel cancels a pending or queued job when cancellation is still allowed.

Bash
curl --fail-with-body --silent --show-error -X POST \
  -H "Authorization: Bearer $PROTEINIQ_API_KEY" \
  "https://proteiniq.io/api/v1/jobs/job_123/cancel"

Successful cancellation returns:

JSON
{
  "object": "job_cancellation",
  "refunded": true,
  "job": {
    "id": "job_123",
    "object": "job",
    "status": "CANCELLED"
  }
}

If the job is already running or terminal, the API returns conflict with details.current_status. A workflow-owned job also returns conflict, without that detail; cancel its workflow run instead.

PreviousToolsNextResults

Table of contents

Get started
OverviewQuickstartAuthentication
Run analyses
ToolsJobsResultsWorkflows
Workspace data
FilesProjectsEvents
Reference
ErrorsRate limitsOpenAPIPython SDKMCP
Appearance
Back to ProteinIQ