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 viainput_formatwhen 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 hascalibration_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
Option 1: SDK Key File (Recommended)
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.
Quickstart: One-Call Submission (Recommended)
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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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.