Skip to main content

Open Quantum Python SDK

A lightweight, modern Python SDK for the Open Quantum Platform.

Features:

  • Management API — list organizations, backend classes, and providers
  • Scheduler API — job categories, upload, prepare, submit, poll, and one-call submit_job()
  • Input formats — OpenQASM (qasm) by default; other formats via input_format when the backend supports them
  • Smart defaults — auto-select execution plan & queue priority from quote
  • Thread-safe auth — Keycloak client-credentials with auto-refresh
  • Automatic output download — download_job_output() returns parsed JSON
  • Calibration download — download_job_calibration() when the job has calibration_data_url

Installation

pip install -U openquantum-sdk
# or local dev:
pip install -e .

Python 3.8+ required.

Source distributions include the tests/ tree so the unit tests can be run from an sdist. Wheels do not install those tests into site-packages. The Qiskit, PennyLane, Cirq, and Qrisp plugins, and openquantum-mcp, use the same split. Package versions live in each pyproject.toml and __version__ (core, Qiskit, and PennyLane 1.0.0; Cirq and Qrisp 0.5.0; MCP 0.2.0).

Authentication

Download from Open Quantum SDK Keys:

{
  "client_id": "s_abc123...",
  "client_secret": "e460c8..."
}
export OPENQUANTUM_SDK_KEY=/path/to/sdk-key.json

Option 2: Direct in Code

from openquantum_sdk.auth import ClientCredentials, ClientCredentialsAuth

auth = ClientCredentialsAuth(
    creds=ClientCredentials(client_id="s_...", client_secret="e460c8...")
)

Option 3: Environment Variables

export OPENQUANTUM_CLIENT_ID=s_...
export OPENQUANTUM_CLIENT_SECRET=e460c8...

OpenQuantumClient.from_env()

Builds a client from those environment credentials and from OPENQUANTUM_SCHEDULER_URL, OPENQUANTUM_MANAGEMENT_URL, OPENQUANTUM_KEYCLOAK_BASE, and OPENQUANTUM_KEYCLOAK_REALM. It does not autoload a saved account. It raises AuthenticationError when no credential resolves.

from openquantum_sdk import OpenQuantumClient

client = OpenQuantumClient.from_env()

OPENQUANTUM_ORGANIZATION_ID is not read by the core client constructor. PennyLane, Cirq, Qrisp, get_backend, and the MCP server use it when organization_id is omitted. The old names OQ_ORG_ID and OQ_SUBCATEGORY_ID are not read.

from openquantum_sdk.clients import SchedulerClient, ManagementClient, JobSubmissionConfig
from openquantum_sdk.enums import ExecutionPlanType, QueuePriorityType
import json

# 1. Instantiate clients (auto-loads auth from env)
scheduler = SchedulerClient()
management = ManagementClient()

try:
    # 2. Discover your Organization ID
    print("Discovering organization...")
    orgs = management.list_user_organizations()
    org_id = orgs.organizations[0].id
    print(f" > Using Org: {orgs.organizations[0].name}")

    # 2.5 Discover available backend providers
    print("\nAvailable providers:")
    providers = management.list_providers()
    for p in providers.providers:
        print(f" > {p.name} ({p.short_code or 'no short code'}) — {p.description}")

    # 2.6 Discover backend classes
    print("\nAvailable backend classes:")
    classes = management.list_backend_classes()
    for bc in classes.backend_classes:
        print(f" > {bc.name} ({bc.short_code or 'no short code'}) — {bc.type}")
        print(f"   ├ Status: {bc.status or 'Unknown'} | Queue depth: {bc.queue_depth or 'N/A'}")
        print(f"   └ Use: '{bc.short_code or bc.id}' in backend_class_id")

    # 3. Define config
    config = JobSubmissionConfig(
        organization_id=org_id,
        backend_class_id="iqm:emerald",
        name="Bell State SDK Quickstart",
        job_subcategory_id="fin:port", # Finance Portfolio Optimization
        shots=100,
        execution_plan="auto",
        queue_priority="auto",
        auto_approve_quote=True,
        verbose=True
    )

    # 4. Submit + wait + get result
    dummy_qasm = b"OPENQASM 2.0; include 'qelib1.inc'; qreg q[2]; creg c[2]; h q[0]; cx q[0],q[1]; measure q -> c;"
    job = scheduler.submit_job(config, file_content=dummy_qasm)

    # 5. Download and print parsed JSON output
    print("\n--- JOB SUCCEEDED ---")
    print(f"Job ID: {job.id}")
    print(f"Status: {job.status}")

    if job.output_data_url:
        output_json = scheduler.download_job_output(job)
        print("\n--- JOB OUTPUT (JSON) ---")
        print(json.dumps(output_json, indent=2))
    else:
        print("No output available.")

    if job.calibration_data_url:
        cal_json = scheduler.download_job_calibration(job)
        print("\n--- CALIBRATION (JSON) ---")
        print(json.dumps(cal_json, indent=2))

except Exception as e:
    print(f"\n--- JOB FAILED ---")
    print(f"Error: {e}")

finally:
    scheduler.close()
    management.close()

Handles everything in one call — including automatic JSON download.

Quickstart: Low-Level (Advanced)

from openquantum_sdk.clients import SchedulerClient, ManagementClient
from openquantum_sdk.models import JobPreparationCreate, JobCreate
from openquantum_sdk.utils import poll_for_status
import json

scheduler = SchedulerClient()
management = ManagementClient()

try:
    # 1. Get org
    org = management.list_user_organizations().organizations[0]

    # 1.5 List providers & backend classes
    print("Providers:")
    for p in management.list_providers().providers:
        print(f" - {p.name} ({p.short_code})")

    print("\nBackend classes:")
    for bc in management.list_backend_classes().backend_classes:
        print(f" - {bc.name} [{bc.type}] — {bc.short_code or bc.id}")

    # 2. Choose IDs
    MY_BACKEND = "iqm:emerald"
    MY_SUBCATEGORY = "fin:port"

    # 3. Upload
    upload_id = scheduler.upload_job_input(file_path="circuit.qasm")

    # 4. Prepare
    prep = JobPreparationCreate(
        organization_id=org.id,
        backend_class_id=MY_BACKEND,
        name="Low-Level Test",
        upload_endpoint_id=upload_id,
        job_subcategory_id=MY_SUBCATEGORY,
        shots=100,
        configuration_data={}
    )
    prep_resp = scheduler.prepare_job(prep)

    # 5. Poll preparation
    def get_prep_status(prep_id: str):
        result = scheduler.get_preparation_result(prep_id)
        done = result.status in ("Completed", "Failed")
        return done, result

    result = poll_for_status(
        get_status_fn=get_prep_status,
        resource_id=prep_resp.id,
        interval=2.0,
        timeout=300
    )

    if result.status == "Failed":
        raise RuntimeError(f"Preparation failed: {result.message or 'Unknown error'}")

    # Quote inspection
    print("\nQuote received:")
    for plan in result.quote:
        print(f" • {plan.name} — Base: {plan.price} credit{'s' if plan.price != 1 else ''}")
        for qp in plan.queue_priorities:
            total = plan.price + qp.price_increase
            print(f"    ├ {qp.name}: +{qp.price_increase} → Total: {total}")
        print(f"    └ Plan ID: {plan.execution_plan_id}")

    # 6. Select cheapest
    cheapest_plan = min(result.quote, key=lambda p: p.price)
    cheapest_prio = min(cheapest_plan.queue_priorities, key=lambda q: q.price_increase)

    # 7. Create job (organization comes from the preparation)
    job = JobCreate(
        job_preparation_id=prep_resp.id,
        execution_plan_id=cheapest_plan.execution_plan_id,
        queue_priority_id=cheapest_prio.queue_priority_id,
    )

    job_resp = scheduler.create_job(job)

    # 8. Poll completion
    def get_job_status(job_id: str):
        job_obj = scheduler.get_job(job_id)
        done = job_obj.status in ("Completed", "Failed", "Canceled")
        return done, job_obj

    final_job = poll_for_status(
        get_status_fn=get_job_status,
        resource_id=job_resp.id,
        interval=5.0,
        timeout=86_400,
    )

    print(f"\nJob finished: {final_job.status}")

    # 9. Download and print JSON output
    if final_job.output_data_url:
        output_json = scheduler.download_job_output(final_job)
        print("\n--- JOB OUTPUT (JSON) ---")
        print(json.dumps(output_json, indent=2))
    else:
        print("No output available.")

finally:
    scheduler.close()
    management.close()

High-Level API: submit_job()

Parameter Type Default Description
config JobSubmissionConfig — All job metadata
file_path str — Input file
file_content bytes — Or pass bytes

JobSubmissionConfig

Field Type Default Notes
organization_id str — Required
backend_class_id str — Required (short code or UUID)
job_subcategory_id str — Required
name str — Required
shots int — Required
configuration_data Dict[str, Any] None
execution_plan str, enum, or UUID "auto" "auto", "public", "private", ExecutionPlanType, or a plan UUID. "auto" picks the cheapest plan
queue_priority str, enum, or UUID "auto" "auto", "standard", "priority", "instant", QueuePriorityType, or a priority UUID. "auto" picks the cheapest priority
auto_approve_quote bool True Set False in notebooks
verbose bool False Print submission progress. Same default on every plugin
job_timeout_seconds int 86400 1 day
input_format str "qasm" OpenQASM by default; other values only if listed in backend supported_formats
submitted_with str "sdk" Client surface for analytics

API Reference

SchedulerClient

Method Returns Description
__init__(auth[ClientCredentialsAuth])
get_job_categories(limit=20, cursor=...) PaginatedJobCategories List top-level categories
get_job_subcategories(category_id, limit=20, cursor=...) PaginatedJobCategories List subcategories
upload_job_input(file_path=... or file_content=...) str Returns upload ID
prepare_job(JobPreparationCreate) JobPreparationResponse Starts preparation
get_preparation_result(preparation_id) JobPreparationResultResponse Includes .quote
wait_for_preparation(preparation_id, timeout=300, interval=2) JobPreparationResultResponse Poll until preparation completes
choose_plan_and_priority(result, execution_plan="auto", queue_priority="auto") PlanSelection Friendly names, enums, and UUIDs. prefer_public=True ranks Public first when the plan is "auto"
create_job(JobCreate) JobRead Submits job
wait_for_job(job_id, timeout=300, interval=5) JobRead Poll until a terminal status. raise_on_timeout and raise_on_failure default to True
get_job(job_id) JobRead Fetch job status
cancel_job(job_id) None Cancel running job
list_jobs(organization_id, limit=20, cursor=..., status=...) PaginatedJobs List your jobs
download_job_output(job) Any Downloads + parses JSON output
download_job_calibration(job) Any Downloads + parses calibration JSON (when tagged)
submit_job(config, file_path=... or file_content=...) JobRead One-call submission + polling

ManagementClient

Method Returns Description
__init__(auth[ClientCredentialsAuth])
list_user_organizations(limit=20, cursor=...) PaginatedOrganizations Your orgs
list_providers(limit=20, cursor=...) PaginatedProviders All backend providers
list_backend_classes(provider_id=None, limit=20, cursor=...) PaginatedBackendClasses Available backends
get_credit_balance(organization_id: str) CreditBalanceRead Get current credit balance

Data Models

Model Key Fields
BackendClassRead id, name, description, type, provider_id, short_code, queue_depth, accepting_jobs, status
ErrorResponse status_code, message: List[str], type, error_code (request id)
JobCategoryRead id, name, short_code
JobCreate job_preparation_id, execution_plan_id, queue_priority_id, optional organization_id
JobList id, backend_class_id, name, status, backend_name, output_data_url, calibration_data_url, credits_used, submitted_at
JobPreparationCreate organization_id, backend_class_id, name, upload_endpoint_id, job_subcategory_id, shots, configuration_data, input_format, submitted_with
JobPreparationResponse id
JobPreparationResultResponse organization_id, backend_class_id, status, name, input_data_url, job_category_id, job_subcategory_id, shots, quote: List[QuotePlan], message, configuration_data
JobPreparationUploadResponse id, url
JobRead id, status, input_data_url, job_preparation_id, execution_plan_id, queue_priority_id, message, output_data_url, calibration_data_url, transaction_id, submitted_at
OrganizationRead id, name
PaginatedBackendClasses backend_classes: List[BackendClassRead], pagination: PaginationInfo
PaginatedJobCategories categories: List[JobCategoryRead], pagination: PaginationInfo
PaginatedJobs jobs: List[JobList], pagination: PaginationInfo
PaginatedOrganizations organizations: List[OrganizationRead], pagination: PaginationInfo
PaginatedProviders providers: List[ProviderRead], pagination: PaginationInfo
PaginationInfo next_cursor
ProviderRead id, name, description, short_code
QueuePriority name, description, price_increase, queue_priority_id
QuotePlan name, price, description, execution_plan_id, queue_priorities: List[QueuePriority]

Utils: poll_for_status()

from openquantum_sdk.utils import poll_for_status
Parameter Type Default Description
get_status_fn Callable[[str], Tuple[bool, Any]] Function to be polled
resource_id str id to be passed to status function: get_status_fn(resource_id)
interval float 5 Seconds to wait before the next status call
timeout float 300 Seconds before polling stops
raise_on_timeout bool True Raise TimeoutError, or return the last result when False

Enums

from openquantum_sdk.enums import ExecutionPlanType, QueuePriorityType
Enum Values
ExecutionPlanType PUBLIC, PRIVATE
QueuePriorityType STANDARD, PRIORITY, INSTANT

CLI (Experimental)

python -m openquantum_sdk --sdk-key ./key.json \
                          --input bell.qasm \
                          --backend "iqm:emerald" \
                          --name "CLI Circuit" \
                          --subcategory "mathematics:linear-systems" \
                          --shots 100 \
                          --auto-approve

Automatically downloads and pretty-prints JSON output.

Short Codes

Backends

Provider Backend Short Code
AQT Ibex-Q1 aqt:ibex-q1
IonQ Forte Enterprise ionq:forte-ent
IonQ Forte-1 ionq:forte-1
IQM Emerald iqm:emerald
IQM Garnet iqm:garnet
Rigetti Cepheus-1-108Q rigetti:cepheus-108q

Note: This list may be modified as backends are added or removed from the platform. For the most up-to-date list, run the following code:

backends = management.list_backend_classes().backend_classes

print('| Name | Short Code | Online |')
for b in backends:
    print(f"| {b.name} | {b.short_code} | {b.accepting_jobs} |")

Subcategories

Category Subcategory Short Code
Chemistry Molecular Ground State Estimation chem:mgse
Chemistry Other (Specify) chem:oth
Chemistry Quantum System Simulation chem:qss
Chemistry Variational Quantum Eigensolver (VQE) chem:vqe
Cryptography Discrete Logarithms crypto:dlog
Cryptography Hash Function Attacks crypto:hash
Cryptography Other (Specify) crypto:oth
Cryptography Shor's Factoring (RSA Cryptanalysis) crypto:shor
Finance Option Pricing fin:opt
Finance Other (Specify) fin:oth
Finance Portfolio Optimization fin:port
Finance Risk Analysis fin:risk
Graph and Network Analysis Graph Connectivity gna:con
Graph and Network Analysis Other (Specify) gna:oth
Graph and Network Analysis Pattern Matching gna:pat
Graph and Network Analysis Quantum Walks on Graphs gna:qwg
Machine Learning Other (Specify) ml:oth
Machine Learning Quantum Classification ml:qcl
Machine Learning Quantum Clustering ml:qcu
Machine Learning Quantum Recommendation Systems ml:qrs
Mathematics Differential Equations math:deq
Mathematics Hidden Subgroup Problems math:hsp
Mathematics Linear Systems (HHL Algorithm) math:hhl
Mathematics Other (Specify) math:oth
Optimization Adiabatic Optimization opt:adi
Optimization Constraint Satisfaction opt:csp
Optimization Other (Specify) opt:oth
Optimization Quantum Approximate Optimization Algorithm (QAOA) opt:qaoa
Other Other (Specify) oth:oth
Physics Hamiltonian Dynamics Simulation phys:hds
Physics Other (Specify) phys:oth
Physics Partition Functions phys:pfn
Physics Topological Invariants (e.g., Jones Polynomials) phys:tin

Note: This list may be modified as categories and subcategories are added or removed. For the most up-to-date list, run the following code:

cats = scheduler.get_job_categories().categories

print('| Category | Subcategory | Short Code |')
for cat in cats:
    subcats = scheduler.get_job_subcategories(cat.short_code).categories
    for subcat in subcats:
        print(f'| {cat.name} | {subcat.name} | {subcat.short_code} |')

Live smoke tests

.github/workflows/sdk-smoke.yml is a manual Actions workflow. It builds the core SDK and the Qiskit, PennyLane, Cirq, and Qrisp plugins from a git ref (empty means main), submits a Bell circuit through each one, and waits until the platform job completes. The QPU input defaults to rigetti:cepheus-1-108q. Choose the dev or prd environment when you run it. See sdk/smoke/README.md.

FAQ

Q: How do I get results as JSON?
A: Use scheduler.download_job_output(job) — returns parsed object.

Q: Why does auto mode fail on some QPUs? A: "auto" selects the cheapest plan and priority, which is often Public + Standard. It is not limited to those two. Friendly names ("public", "private", "standard", "priority", "instant"), enums, and UUIDs select that option exactly. If you need a specific plan or a faster queue, pass it explicitly. The MCP server passes prefer_public=True so Spark credits can apply; submit_job() does not.

Q: Can I hide the public plan citation notice?
A: Setting OPENQUANTUM_HIDE_CITATION_NOTICE=true will omit the citation notice from output.

Metadata

Release files for openquantum-sdk 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openquantum-sdk 1.0.0
File Size Uploaded Provenance Actions
openquantum_sdk-1.0.0.tar.gz 61.4 kB Without provenance Details for openquantum_sdk-1.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for openquantum-sdk 1.0.0
File Interpreter ABI Platform Actions
openquantum_sdk-1.0.0-py3-none-any.whl Python 3 none any Details for openquantum_sdk-1.0.0-py3-none-any.whl

Total release size: 109.7 kB

Release files / openquantum_sdk-1.0.0.tar.gz

Download URL openquantum_sdk-1.0.0.tar.gz
Size 61.4 kB
Tags Source
SHA-256 checksum
How to use checksums
e86f111d4752dcd60e3232a3a738568ec22200336e1ddfc5a175abea690afcd3
BLAKE2b-256 checksum
How to use checksums
2cfcf1b2f0916d5ac99a8df684ee575720a1b6809caf782eb55579e699f5ddf5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / openquantum_sdk-1.0.0-py3-none-any.whl

Download URL openquantum_sdk-1.0.0-py3-none-any.whl
Size 48.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a189be978d1e52682c362df1301e1e5185b415081ac0b58661824aff4467bdfc
BLAKE2b-256 checksum
How to use checksums
0accd09fc394eaa7248e89f372d0d4b47d826732701867f4c54af064cf1557b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for openquantum-sdk 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page