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).

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()), not a job ID string.

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
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,
)
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)