Skip to content

Job Submission

The Core SDK provides a high-level submit_job() method that handles the entire job lifecycle in a single call: upload, prepare, submit, and wait for completion.

JobSubmissionConfig

JobSubmissionConfig defines all parameters for a job submission:

from openquantum_sdk.clients import JobSubmissionConfig

config = JobSubmissionConfig(
    backend_class_id="ionq:forte-1",
    name="My Quantum Job",
    job_subcategory_id="oth:oth",
    shots=1024,
)

Required Fields

Field Type Description
backend_class_id str Target backend (UUID or short code, e.g., "ionq:forte-1")
name str Display name for the job
job_subcategory_id str Job subcategory (UUID or short code, e.g., "oth:oth")
shots int Number of measurement shots

Optional Fields

Field Type Default Description
organization_id str None Organization UUID. Auto-discovered if not provided.
configuration_data dict None Backend-specific configuration data.
execution_plan str "auto" "auto", or a specific ExecutionPlanType enum value.
queue_priority str "auto" "auto", or a specific QueuePriorityType enum value.
auto_approve_quote bool True Automatically approve the pricing quote.
verbose bool False Print progress messages during submission.
job_timeout_seconds int 86400 Maximum time to wait for job completion (1 day).
submitted_with str "sdk" Client surface for analytics ("sdk", "cli", etc.).
input_format str "qasm" Circuit language family (default OpenQASM). Other values may be accepted when listed in the backend's supported_formats.

Input formats

Backends advertise accepted input language families via constraint_data.supported_formats (defaults to ["qasm"] when omitted).

input_format What you upload Notes
"qasm" (default) OpenQASM 2 or 3 text Version is detected from the file header (OPENQASM 2.0 / OPENQASM 3.0).
Other values Backend-specific input Only valid if the backend lists them in supported_formats.
# OpenQASM (default) — omit input_format or set "qasm"
config = JobSubmissionConfig(
    backend_class_id="ionq:forte-1",
    name="Bell State",
    job_subcategory_id="oth:oth",
    shots=1024,
    input_format="qasm",
)
job = scheduler.submit_job(config, file_path="circuit.qasm")

Low-level JobPreparationCreate accepts the same input_format field:

prep = JobPreparationCreate(
    organization_id=org_id,
    backend_class_id="ionq:forte-1",
    name="Manual Job",
    upload_endpoint_id=upload_id,
    job_subcategory_id="oth:oth",
    shots=1024,
    input_format="qasm",
)

Note

If you declare an input_format the backend does not list in supported_formats, job preparation fails with a validation error.

Execution Plan and Queue Priority

When set to "auto" (the default), the SDK selects the cheapest available execution plan and the lowest-cost queue priority. You can also specify explicit values:

from openquantum_sdk.enums import ExecutionPlanType, QueuePriorityType

config = JobSubmissionConfig(
    backend_class_id="ionq:forte-1",
    name="Priority Job",
    job_subcategory_id="oth:oth",
    shots=1024,
    execution_plan=ExecutionPlanType.PUBLIC,
    queue_priority=QueuePriorityType.PRIORITY,
)

Submitting a Job

Use submit_job() with either a file path or raw bytes:

From a File

job = scheduler.submit_job(config, file_path="circuit.qasm")

From a String

qasm = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0],q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];
"""

job = scheduler.submit_job(config, file_content=qasm.encode("utf-8"))

Warning

file_content must be bytes, not str. Encode your string with .encode("utf-8").

Downloading Results

After a job completes, download the output:

output = scheduler.download_job_output(job)
print(output)

The download_job_output() method fetches the result from the presigned URL in the job's output_data_url field and parses it as JSON.

Note

download_job_output() takes a JobRead object (returned by submit_job() / get_job()), not a job ID string.

Result shape depends on the backend (for example a bitstring counts map, or another backend-specific JSON document).

Calibration data

Some backends tag a calibration snapshot on the completing execution. When present, the job includes a presigned calibration_data_url (same pattern as output_data_url).

job = scheduler.get_job(job.id)  # refresh URLs if needed

if job.calibration_data_url:
    cal = scheduler.download_job_calibration(job)
    print(cal)
else:
    print("No calibration tagged on this job")
Field / method Description
job.calibration_data_url Presigned download URL, or None if no calibration was tagged
scheduler.download_job_calibration(job) GET + parse JSON for that URL

Calibration is optional. Backends that report calibration to the platform set it when the execution completes successfully.

Portal

On Jobs, open the menu on a job that has calibration data and choose Download calibration data.

Error Handling

The SDK raises specific exceptions for API errors:

from openquantum_sdk.models import APIError

try:
    job = scheduler.submit_job(config, file_path="circuit.qasm")
except APIError as e:
    print(f"Status: {e.error_response.status_code}")
    print(f"Message: {e.error_response.message}")
    print(f"Request ID: {e.error_response.error_code}")
except TimeoutError as e:
    print(f"Job timed out: {e}")
except RuntimeError as e:
    print(f"Submission error: {e}")

Common error scenarios:

HTTP Status Meaning
401 Invalid or expired credentials
402 Insufficient credits
409 Active job limit reached (max 10 per organization)

Verbose Mode

Enable verbose output to see progress during submission:

config = JobSubmissionConfig(
    backend_class_id="ionq:forte-1",
    name="Verbose Job",
    job_subcategory_id="oth:oth",
    shots=1024,
    verbose=True,
)

job = scheduler.submit_job(config, file_path="circuit.qasm")

Output:

Step 1/5: Uploading job input...
Step 2/5: Preparing job and fetching quote...
  > Preparation status: Completed
  > Preparation complete.
Step 3/5: Processing quote...
  > Auto-selected plan: Public Plan (2 credits)
  > Auto-selected priority: Standard Queue (+0)
Step 3/5: Quote approved automatically (auto_approve_quote=True)
Step 4/5: Submitting job (Public Plan + Standard Queue)...
Step 5/5: Job 'abc123...' created. Waiting for completion (timeout: 86400s)...
  > Job status: Completed
  > Job finished with status: Completed

Job Categories

Every job requires a job_subcategory_id (e.g., "oth:oth"). The high-level submit_job() accepts short codes and resolves them automatically, but for low-level submission you may need to discover the valid category and subcategory UUIDs.

Listing Categories

categories = scheduler.get_job_categories()
for cat in categories.categories:
    print(f"{cat.id}: {cat.name} ({cat.short_code})")

Listing Subcategories

subcategories = scheduler.get_job_subcategories(category_id="<category-uuid>")
for sub in subcategories.categories:
    print(f"{sub.id}: {sub.name} ({sub.short_code})")

Both methods support pagination with limit and cursor parameters.

Polling Utility

The SDK provides a generic poll_for_status utility for polling any status endpoint. It is used internally by submit_job() to wait for job preparation and completion, but you can also use it directly for low-level workflows.

from openquantum_sdk import poll_for_status

result = poll_for_status(
    get_status_fn=my_status_checker,
    resource_id="resource-uuid",
    interval=5,       # seconds between polls (default: 5)
    timeout=300,       # max seconds before TimeoutError (default: 300)
)
Parameter Type Default Description
get_status_fn Callable[[str], tuple[bool, Any]] -- Takes a resource ID, returns (is_done, result)
resource_id str -- ID passed to get_status_fn on each call
interval int 5 Seconds between polling attempts
timeout int 300 Maximum seconds before TimeoutError is raised

Example with job status polling:

def check_job(job_id):
    job = scheduler.get_job(job_id)
    return job.status in ("Completed", "Failed", "Cancelled"), job

job = poll_for_status(check_job, "your-job-uuid", interval=10, timeout=600)
print(f"Final status: {job.status}")

Low-Level Submission

For finer control, you can use the individual methods instead of submit_job():

from openquantum_sdk.models import JobPreparationCreate, JobCreate

# Step 1: Upload
upload_id = scheduler.upload_job_input(file_path="circuit.qasm")

# Step 2: Prepare (input_format defaults to "qasm"; set only if the backend needs another format)
prep = JobPreparationCreate(
    organization_id="your-org-uuid",
    backend_class_id="ionq:forte-1",
    name="Manual Job",
    upload_endpoint_id=upload_id,
    job_subcategory_id="oth:oth",
    shots=1024,
    input_format="qasm",
)
prep_resp = scheduler.prepare_job(prep)

# Step 3: Poll preparation
result = scheduler.get_preparation_result(prep_resp.id)

# Step 4: Submit
job_create = JobCreate(
    organization_id="your-org-uuid",
    job_preparation_id=prep_resp.id,
    execution_plan_id=result.quote[0].execution_plan_id,
    queue_priority_id=result.quote[0].queue_priorities[0].queue_priority_id,
)
job = scheduler.create_job(job_create)

# Step 5: Poll job status
job = scheduler.get_job(job.id)