Python SDKqly-sdk 0.2MIT

Qly from your terminal

qly-sdk is the Python client for Qly. Write a circuit in OpenQASM or Qiskit, submit it to real quantum hardware or a simulator, and pull the results back as Python objects. Everything the Compute page does, scriptable.

Get an API key →qly-sdk on PyPI

Overview

The package name on PyPI is qly-sdk; everything else is just qly. You import qly in Python, and the install also puts a qly command on your PATH for shell workflows and CI.

Submit
OpenQASM strings or Qiskit circuits, to QPUs and simulators across providers.
Poll
Blocking run(), or submit() and check status yourself. Counts come back as dicts.
Operate
List devices, check balance, script the whole loop from a shell or notebook.

Jobs submitted through the SDK land on the same pipeline as the Compute page: they show up on your Jobs page with full histograms, and they bill against the same prepaid balance.

Install & authenticate

shell
pip install qly-sdk export QLY_API_KEY=qly_live_... # the key from your API Keys page

Sign in and create a key on the API Keys page. The secret is shown once and looks like qly_live_…. Set QLY_API_KEY in your environment and construct the client with no arguments, as every example below does, or pass it as Qly(api_key=…).

In Google Colab

In a notebook, install with !pip and ask for the key when the cell runs, so it never sits in the notebook text you might share. Add the [qiskit] extra if you will pass Qiskit circuits.

Colab cell · Python
!pip install -q "qly-sdk[qiskit]" import getpass, os os.environ["QLY_API_KEY"] = getpass.getpass("Qly API key: ")

Quickstart

A Bell pair on a free simulator in a dozen lines. run() submits and blocks until the job finishes, then hands you the counts.

bell.py · Python
from qly import Qly client = Qly() # reads QLY_API_KEY bell = """ OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; creg c[2]; h q[0]; cx q[0], q[1]; measure q -> c; """ job = client.run(bell, provider="clifft", device="clifft-sim", shots=1024) print(job.counts) # {'00': 503, '11': 521}

Simulators are free and the code path to real hardware is identical, so iterate on a simulator first. The Real hardware section below has the one example that runs on a QPU.

Two free simulators are listed. clifft-sim draws random shots, so counts vary between runs like a real device, and it accepts any gate. ionq / simulator reports the ideal probabilities scaled to your shot count, so repeated runs match exactly, and it accepts a smaller gate set: anything it cannot run is refused with a message naming the instruction rather than skipped.

Submit & poll separately

Real QPUs queue, so blocking is not always what you want. submit() returns immediately with a job handle; wait() blocks until it reaches a terminal state, or poll by hand with get_job().

Python
from qly import Qly client = Qly() bell = """ OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; creg c[2]; h q[0]; cx q[0], q[1]; measure q -> c; """ job = client.submit(bell, provider="clifft", device="clifft-sim", shots=1024) print(job.id, job.status) # a QPU that is still queued shows 'PENDING' here job = client.wait(job) # blocks until terminal, raises on failure print(job.counts) # or poll by hand: job = client.get_job(job.id) if job.done: print(job.results)

From a Qiskit circuit

Install the extra with pip install "qly-sdk[qiskit]" and pass a QuantumCircuit directly; no manual QASM export needed.

Python
# pip install "qly-sdk[qiskit]" from qiskit import QuantumCircuit from qly import Qly # Four qubits, each in an equal superposition, all measured: 16 outcomes. qc = QuantumCircuit(4, 4) qc.h(range(4)) qc.measure(range(4), range(4)) client = Qly() job = client.run(circuit=qc, provider="clifft", device="clifft-sim", shots=1024) print(job.counts) # 16 four-bit strings, about 64 shots each

Command line

The install ships a qly command, so you can run circuits without writing any Python. Set QLY_API_KEY, or run qly configure once in a terminal to store the key in ~/.config/qly/; configure prompts for the key, so in a notebook use the environment variable instead.

shell
pip install qly-sdk export QLY_API_KEY=qly_live_... cat > bell.qasm <<'EOF' OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; creg c[2]; h q[0]; cx q[0], q[1]; measure q -> c; EOF qly devices # what can I run on? qly balance qly submit bell.qasm --provider clifft --device clifft-sim --shots 1024 --wait qly jobs --limit 10 # recent jobs qly job <job-id> # status + histogram; the id is printed by submit

submit --wait polls until the job finishes and prints the counts. Every command takes --json for machine-readable output, and --api-key / QLY_API_KEY override the stored key, which is what you want in CI.

Devices & balance

Enumerate every device your account can target, with qubit counts and simulator flags, and check your balance before a big batch.

Python
from qly import Qly client = Qly() for d in client.devices(): print(d.provider, d.id, d.qubits, "sim" if d.is_simulator else "qpu") print(client.balance().formatted) # '$5.00'

Real hardware

A real QPU queues and costs credit, so this is the one example that runs on one. Pick the machine from client.devices() or the Router page on the day: queues and each machine's readings change, and ibm_marrakesh below is an example, not a recommendation. On IBM devices you can also request Pauli expectation values instead of raw shot counts, which is the primitive variational algorithms like VQE consume.

hardware.py · Python
from qly import Qly client = Qly() bell = """ OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; creg c[2]; h q[0]; cx q[0], q[1]; measure q -> c; """ ansatz_qasm = """ OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; creg c[2]; ry(0.6) q[0]; cx q[0], q[1]; """ device = "ibm_marrakesh" # an id from client.devices(), or pick from qly.app/router # Counts job = client.run(bell, provider="ibm", device=device, shots=512) print(job.counts) # Expectation values (IBM only) job = client.run( ansatz_qasm, provider="ibm", device=device, primitive="estimator", observables=["ZZ", "IZ", "ZI"], shots=512, ) print(job.results) # {'evs': [...], 'stds': [...]}

Error handling

Failures raise typed exceptions with the fields you need to react programmatically:

AuthenticationErrormissing, invalid, or revoked key
InsufficientBalanceErrornot enough credit; carries .estimated_cents and .balance_cents
RateLimitErrortoo many submissions; carries .retry_after
JobFailedErrorjob ended FAILED / ERROR / CANCELLED; .job has the detail
JobTimeoutErrorrun() or wait() timed out
APIErroranything else; carries .status_code and .payload
Python
from qly import Qly, AuthenticationError client = Qly(api_key="qly_live_" + "0" * 64) # a key that does not exist try: client.devices() except AuthenticationError as e: print(e) # says the key is invalid and where to create a new one

Configuration

ArgumentEnv varDefault
api_keyQLY_API_KEYrequired
base_urlQLY_BASE_URLhttps://qly.app

Ready to run something? Create a key, then submit your first circuit from the shell in under a minute.

Get an API key →Prefer the IDE? Tutorials →